sql >> Databáze >  >> NoSQL >> MongoDB

Vypočítaná pole podle skupin v MongoDB

Ve skutečnosti můžete něco takového udělat nejprve s "projektem", ale pro mě je trochu neintuitivní vyžadovat $project fáze před hrou:

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

Jak jsem řekl, neintuitivní, protože byste měli být schopni toto vše deklarovat pod $group fázi, ale zdá se, že pomocníci tímto způsobem nefungují. Serializace přijde trochu legrační (zabalí argumenty operátoru data do polí), ale zdá se, že funguje. Ale přesto se jedná spíše o dvě fáze potrubí než o jednu.

Co je s tím za problém? Oddělením fází a fází si část „projekt“ vynutí zpracování všech dokumentů v potrubí, aby získala vypočítaná pole, to znamená, že projde vším, než se přesune do skupinové fáze.

Rozdíl v době zpracování lze jasně vidět spuštěním dotazů v obou formách. Se samostatnou fází projektu trvá na mém hardwaru třikrát déle provedení než dotaz, kde se všechna pole počítají během operace „skupiny“.

Zdá se tedy, že jediným současným způsobem, jak to správně zkonstruovat, je postavit objekt potrubí sami:

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

Nebo pokud se vám zdá, že je to všechno stručné, můžete vždy pracovat se zdrojem JSON a analyzovat to. Ale samozřejmě musí být platný 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. Jedinečný atribut SailsJS a Mongo je ignorován

  2. Získejte odlišné hodnoty z pole na základě podmínek v poli

  3. Lze nastavit frekvenci srdečního tepu nebo časový limit repliky?

  4. mongoDB 32bitový limit 2 GB, osvědčené postupy