13

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 }
        }
      }
   ]
)

または一般的に、計算フィールドでグループ化するにはどうすればよいですか?

4

2 に答える 2

20

実際には、最初に「プロジェクト」でこのようなことを行うことができますが、私にとっては、$project事前に段階を必要とするのは少し直感に反しています。

    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が、ヘルパーはこのようには機能しないようです。シリアライゼーションは少しおかしくなります (日付演算子の引数を配列でラップします) が、うまくいくようです。それでも、これは 1 つではなく 2 つのパイプライン ステージです。

これの何が問題なのですか?ステージを分離することにより、「プロジェクト」部分は、計算フィールドを取得するためにパイプライン内のすべてのドキュメントの処理を強制します。つまり、グループ ステージに進む前にすべてを通過します。

両方の形式でクエリを実行すると、処理時間の違いが明確にわかります。別のプロジェクト ステージでは、私のハードウェアでは、「グループ」操作中にすべてのフィールドが計算されるクエリよりも実行に 3 倍の時間がかかります。

したがって、これを適切に構築する現在の唯一の方法は、パイプライン オブジェクトを自分で構築することです。

    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);
于 2014-08-22T04:16:42.000 に答える