java - MongoDB中计算的分组字段

标签 java mongodb spring-data aggregation-framework spring-mongodb

对于 MongoDB 文档中的这个示例,如何使用 MongoTemplate 编写查询?

db.sales.aggregate(
   [
      {
        $group : {
           _id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } },
           totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } },
           averageQuantity: { $avg: "$quantity" },
           count: { $sum: 1 }
        }
      }
   ]
)

或者一般来说,我如何按计算字段分组?

最佳答案

你实际上可以先用“项目”做这样的事情,但对我来说,事先要求 $project 阶段有点违反直觉: p>

    Aggregation agg = newAggregation(
        project("quantity")
            .andExpression("dayOfMonth(date)").as("day")
            .andExpression("month(date)").as("month")
            .andExpression("year(date)").as("year")
            .andExpression("price * quantity").as("totalAmount"),
        group(fields().and("day").and("month").and("year"))
            .avg("quantity").as("averavgeQuantity")
            .sum("totalAmount").as("totalAmount")
            .count().as("count")
    );

就像我说的那样,违反直觉,因为您应该能够在 $group 阶段声明所有这些,但助手似乎并没有这样做方法。序列化有点有趣(用数组包装日期运算符参数)但它似乎确实有效。但是,这仍然是两个流水线阶段,而不是一个。

这有什么问题?好吧,通过将阶段分开,“项目”部分会强制处理管道中的所有文档以获得计算字段,这意味着它在进入小组阶段之前会通过所有内容。

通过以两种形式运行查询可以清楚地看到处理时间的差异。使用单独的项目阶段,在我的硬件上执行的时间是在“组”操作期间计算所有字段的查询的三倍。

因此,目前唯一正确构建它的方法似乎是自己构建管道对象:

    ApplicationContext ctx =
            new AnnotationConfigApplicationContext(SpringMongoConfig.class);
    MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");

    BasicDBList pipeline = new BasicDBList();
    String[] multiplier = { "$price", "$quantity" };

    pipeline.add(
        new BasicDBObject("$group",
            new BasicDBObject("_id",
                new BasicDBObject("month", new BasicDBObject("$month", "$date"))
                    .append("day", new BasicDBObject("$dayOfMonth", "$date"))
                    .append("year", new BasicDBObject("$year", "$date"))
            )
            .append("totalPrice", new BasicDBObject(
                "$sum", new BasicDBObject(
                    "$multiply", multiplier
                )
            ))
            .append("averageQuantity", new BasicDBObject("$avg", "$quantity"))
            .append("count",new BasicDBObject("$sum",1))
        )
    );

    BasicDBObject aggregation = new BasicDBObject("aggregate","collection")
        .append("pipeline",pipeline);

    System.out.println(aggregation);

    CommandResult commandResult = mongoOperation.executeCommand(aggregation);

或者,如果所有这些对您来说似乎都很简洁,那么您可以随时使用 JSON 源并对其进行解析。但当然,它必须是有效的 JSON:

    String json = "[" +
        "{ \"$group\": { "+
            "\"_id\": { " +
                "\"month\": { \"$month\": \"$date\" }, " +
                "\"day\": { \"$dayOfMonth\":\"$date\" }, " +
                "\"year\": { \"$year\": \"$date\" } " +
            "}, " +
            "\"totalPrice\": { \"$sum\": { \"$multiply\": [ \"$price\", \"$quantity\" ] } }, " +
            "\"averageQuantity\": { \"$avg\": \"$quantity\" }, " +
            "\"count\": { \"$sum\": 1 } " +
        "}}" +
    "]";

    BasicDBList pipeline = (BasicDBList)com.mongodb.util.JSON.parse(json);

关于java - MongoDB中计算的分组字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25437823/

相关文章:

java - Spring Data、EclipseLink 和 SimpleLoadTimeWeaver;由不同 ClassLoader 加载的域类

java 拖放

mongodb:我应该总是在更新时使用 'safe' 选项吗

MongoDB同时查询嵌套文档字段

java - JDBCConnectionException 有时会出现 spring 数据和 amazon RDS

java - 使用多个 Spring Boot 和 JDBC 数据源

java - 在不同的 Spock 测试中重用 Spring 应用程序上下文

java - XPage:是否可以从 Java 调用 SSJS 函数?

windows - 如何在mongo shell中每页显示命令输出页

java - 在 HP-UX 机器上忽略高于 32767 的 DB2 queryDataSize