sql >> Database teknologi >  >> NoSQL >> MongoDB

Beregnet grupper efter felter i MongoDB

Du kan faktisk gøre sådan noget med "projekt" først, men for mig er det lidt kontraintuitivt at kræve et $project etape før hånden:

    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")
    );

Som jeg sagde, kontraintuitivt, da du bare burde være i stand til at erklære alt dette under $group fase, men hjælperne ser ikke ud til at arbejde på denne måde. Serialiseringen kommer lidt sjov ud (omslutter datooperatørargumenterne med arrays), men det ser ud til at virke. Men stadigvæk er dette to pipeline-faser snarere end én.

Hvad er problemet med dette? Ved at adskille stadierne, tvinger "projektdelen" behandlingen af ​​alle dokumenterne i pipelinen for at få de beregnede felter, det betyder, at den passerer gennem alt, før den går videre til gruppefasen.

Forskellen i behandlingstid kan tydeligt ses ved at køre forespørgslerne i begge former. Med en separat projektfase tager min hardware tre gange længere tid at udføre end forespørgslen, hvor alle felter beregnes under "gruppe"-operationen.

Så det ser ud til, at den eneste nuværende måde at konstruere dette korrekt på er ved selv at bygge pipeline-objektet:

    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);

Eller hvis alt det virker for dig, så kan du altid arbejde med JSON-kilden og analysere den. Men det skal selvfølgelig være gyldig 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. Advarsel om fortabelse af MongoDB-mangos

  2. MongoDB $toInt

  3. MongoDB:kontroller forbindelsen til DB

  4. ude af stand til at opdatere ejendommen createAt i mongoose?