MongoDB Count, основанный на выводе по одному полю - PullRequest
0 голосов
/ 30 апреля 2018

Предположим, у меня есть следующий набор данных,

//listings collection

{
  "city": New York,
  "beds": 2,
  "build": concrete
}

{
  "city": New York,
  "beds": 4,
  "build": wood
}

{
  "city": New York,
  "beds": 3,
  "build": asphalt
}

{
  "city": New York,
  "beds": 1,
  "build": concrete
}

Я могу получить количество следующих средних коек с помощью следующего запроса

        db.listings.aggregate(
            [  
                {  
                    $match: {  
                        "city": "New York"
                    }
                },
                {  
                    $group: {  
                        "_id": null,
                        "Avg-Beds": {  
                            $avg:"$beds
                         }
                    }
                }
            ])

Что круто, но то, что я действительно ищу, это что-то вроде

{
    "Avg-Beds": 2
    "Build" {
                "Asphalt" : 1,
                "Wood": 1,
                "Concrete": 2

}

Итак, я хочу усреднить кровати, но я хочу посчитать вывод поля "build" одновременно. Как это достижимо с mongodb?

Еще лучше было бы что-то вроде вывода

"Build": {
           "Asphalt": "25%"
 }

Что даст процентное значение. Обратите внимание, что у меня нет предопределенного набора "build" полей вывода.

1 Ответ

0 голосов
/ 30 апреля 2018

Вы можете попробовать ниже агрегации:

db.listings.aggregate([
    {
        $match: { "city": "New York" }
    },
    {
        $group: {
            _id: null,
            avg: { $avg: "$beds" },
            docs: { $push: "$$ROOT" }
        }
    },
    {
        $unwind: "$docs"
    },
    {
        $group: {
            _id: "$docs.build",
            avg: { $first: "$avg" },
            beds: { $sum: "$docs.beds" }
        }
    },
    {
        $group: {
            _id: null,
            avg: { $first: "$avg" },
            total: { $sum: "$beds" },
            Build: { $push: { k: "$_id", v: "$beds" } }
        }
    },
    {
        $addFields: {
            Build: {
                $map: {
                    input: "$Build",
                    as: "b",
                    in: {
                        k: "$$b.k",
                        v: { $divide: [ "$$b.v", "$total" ] }
                    }
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            avg: 1,
            Build: { $arrayToObject: "$Build" }
        }
    }
])

Дело в том, что вам нужно несколько независимых агрегаций, чтобы вы могли выполнить сначала одну ($avg), а затем встроить ее результат в каждый документ вашей коллекции (поместив все документы в поле docs и размотав это поле) , Затем вы можете построить массив из пар k - v, чтобы применить $ arrayToObject для представления процентов.

В результате вы получите:

{ "avg" : 2.5, "Build" : { "asphalt" : 0.3, "wood" : 0.4, "concrete" : 0.3 } }
...