Основная концепция для "реверса $unwind
" , конечно, равна $push
. Поэтому в основном это то, что вы делаете, с некоторым дополнительным использованием $first
, где это уместно, а также $arrayToObject
и $objectToArray
вместе с $filter
, поскольку не нужно указывать каждое поле в документе, особенно когда в документе на самом деле имеется намного больше полей, чем представлено в вопросе.
Следующее является довольно общим и не имеет значения, сколько других полей присутствуют в документе:
db.collection.aggregate([
{ "$group": {
"_id": "$Herbivore species",
"count": { "$sum": 1 },
"Herbivore subfamily": { "$first": "$Herbivore subfamily" },
"records": {
"$push": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": [ "$$this.k", ["Herbivore subfamily", "Herbivore species"] ] } }
}
}
}
}
}}
])
Это приведет к такому результату:
{
"_id" : "Agrius cingulata",
"count" : 1,
"Herbivore subfamily" : "Sphinginae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24cc",
"voucher" : "77-SRNP-4",
"Collection Date" : "1977-06-06T06:00:00.000Z",
"Latitude" : "10.83764",
"Longitude" : "-85.61871"
}
]
}
{
"_id" : "Xylophanes turbata",
"count" : 2,
"Herbivore subfamily" : "Macroglossinae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24ea",
"voucher" : "78-SRNP-10",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
},
{
"_id" : "5ba6b67ab22f62939eba24eb",
"voucher" : "78-SRNP-10.02",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
}
]
}
Не точно , что было задано в вопросе, поскольку, конечно, точно не показывает "ключи" результата в том виде, в котором он был запрошен. Но это может быть исправлено с помощью второй стадии $group
вместе с теми же операторами, которые были показаны ранее:
db.collection.aggregate([
{ "$group": {
"_id": "$Herbivore species",
"count": { "$sum": 1 },
"Herbivore subfamily": { "$first": "$Herbivore subfamily" },
"records": {
"$push": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": [ "$$this.k", ["Herbivore subfamily", "Herbivore species"] ] } }
}
}
}
}
}},
{ "$group": {
"_id": null,
"content": {
"$mergeObjects": {
"$arrayToObject": [[
{ "k": "$_id",
"v": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$ne": ["$$this.k", "_id"] }
}
}
}
}
]]
}
}
}},
{ "$replaceRoot": { "newRoot": "$content" } }
])
Что возвращает:
{
"Xylophanes turbata" : {
"count" : 2,
"Herbivore subfamily" : "Macroglossinae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24ea",
"voucher" : "78-SRNP-10",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
},
{
"_id" : "5ba6b67ab22f62939eba24eb",
"voucher" : "78-SRNP-10.02",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
}
]
},
"Agrius cingulata" : {
"count" : 1,
"Herbivore subfamily" : "Sphinginae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24cc",
"voucher" : "77-SRNP-4",
"Collection Date" : "1977-06-06T06:00:00.000Z",
"Latitude" : "10.83764",
"Longitude" : "-85.61871"
}
]
}
}
Или, если вы предпочитаете (так как это не меняет объем возвращаемых данных в любом случае), вы можете просто «преобразовать» в форму «ключ / значение» возвращаемого документа в клиентском коде после того, как результат будет возвращен из MongoDB. Простой пример JavaScript-оболочки:
db.collection.aggregate([
{ "$group": {
"_id": "$Herbivore species",
"count": { "$sum": 1 },
"Herbivore subfamily": { "$first": "$Herbivore subfamily" },
"records": {
"$push": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": [ "$$this.k", ["Herbivore subfamily", "Herbivore species"] ] } }
}
}
}
}
}},
/*
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": [[
{ "k": "$_id",
"v": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$ne": ["$$this.k", "_id"] }
}
}
}
}
]]
}
}}
*/
]).toArray().reduce((o,{ _id, ...rest }) => ({ ...o, [_id]: rest }),{})
И тот же результат:
{
"Xylophanes turbata" : {
"count" : 2,
"Herbivore subfamily" : "Macroglossinae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24ea",
"voucher" : "78-SRNP-10",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
},
{
"_id" : "5ba6b67ab22f62939eba24eb",
"voucher" : "78-SRNP-10.02",
"Collection Date" : "1978-05-20T06:00:00.000Z",
"Latitude" : "10.80212",
"Longitude" : "-85.65372"
}
]
},
"Agrius cingulata" : {
"count" : 1,
"Herbivore subfamily" : "Sphinginae",
"records" : [
{
"_id" : "5ba6b67ab22f62939eba24cc",
"voucher" : "77-SRNP-4",
"Collection Date" : "1977-06-06T06:00:00.000Z",
"Latitude" : "10.83764",
"Longitude" : "-85.61871"
}
]
}
}
Вероятно, главное, что нужно понять, это "агрегирование" (то, что делает первый представленный этап), вероятно, это то, что вы действительно хотите, чтобы сервер баз данных делал. Вы можете использовать «причудливые» операторы или , а не , в зависимости от имеющейся версии MongoDB. Однако «преобразования конечного результата» , как было продемонстрировано как вторая фаза в примерах, приведенных здесь, вероятно, является чем-то, что вы действительно хотите сделать вместо этого, принимая клиентский и обрабатывающий код. Обычно это намного проще и понятнее.