sql >> データベース >  >> NoSQL >> MongoDB

MongoDBで計算されたgroup-byフィールド

    実際には、最初に「プロジェクト」を使用してこのようなことを行うことができますが、私にとっては、 $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);
    


    1. MongoDB $ elemMatch $ in

    2. mongodbの複数の制限条件

    3. MongoDBクエリ、userIDですべて検索

    4. PHPMongoDBマップがdbアサーションの失敗を減らす