MongoDB совокупная вложенная группировка - PullRequest
0 голосов
/ 09 декабря 2018

У меня есть коллекция активов, в которой есть данные типа

{
     "_id" : ObjectId("5bfb962ee2a301554915"),
     "users" : [
                 "abc.abc@abc.com",
                 "abc.xyz@xyz.com"
          ],
     "remote" : {
                "source" : "dropbox",
                "bytes" : 1234
}
{
     "_id" : ObjectId("5bfb962ee2a301554915"),
     "users" : [
                 "pqr.pqr@pqr.com",
          ],
     "remote" : {
                "source" : "google_drive",
                "bytes" : 785
}
{
     "_id" : ObjectId("5bfb962ee2a301554915"),
     "users" : [
                 "abc.abc@abc.com",
                 "abc.xyz@xyz.com"
          ],
     "remote" : {
                "source" : "gmail",
                "bytes" : 5647
}

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

{
    "_id" : "abc.abc@abc.com",
    "bytes" : {
                 "google_drive": 1458,
                 "dropbox" : 1254
              }
}

IЯ не получаю, как получить вложенный вывод с помощью группировки.Я пытался с запросом

db.asset.aggregate(
     [
        {$unwind : '$users'},
        {$group:{
                 _id:
                    {'username': "$users", 
                    'source': "$remote.source", 
                    'total': {$sum: "$remote.bytes"}} }
        }
    ]
)

Таким образом, я получаю результат с повторным именем пользователя.

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

С MongoDb 3.6 и новее вы можете использовать оператор $arrayToObject в выражении $mergeObjects и$replaceRoot конвейер, чтобы получить желаемый результат.

Вам потребуется запустить следующий агрегированный конвейер:

db.asset.aggregate([
    { "$unwind": "$users" },
    { "$group": {
        "_id": { 
            "users": "$users",
            "source": "$remote.source" 
        },
        "totalBytes": { "$sum": "$remote.bytes" }
    } },
    { "$group": {
        "_id": "$_id.users",
        "counts": {
            "$push": {
                "k": "$_id.source",
                "v": "$totalBytes"
            }
        }
    } },
    { "$replaceRoot": { 
        "newRoot": { 
            "$mergeObjects": [ 
                { "bytes": { "$arrayToObject": "$counts" } }, 
                "$$ROOT" 
            ] 
        } 
    } },
    { "$project": { "counts": 0 } }   
])

, что дает

/* 1 */
{
    "bytes" : {
        "gmail" : 5647.0,
        "dropbox" : 1234.0
    },
    "_id" : "abc.abc@abc.com"
}

/* 2 */
{
    "bytes" : {
        "google_drive" : 785.0
    },
    "_id" : "pqr.pqr@pqr.com"
}

/* 3 */
{
    "bytes" : {
        "gmail" : 5647.0,
        "dropbox" : 1234.0
    },
    "_id" : "abc.xyz@xyz.com"
}

с использованием приведенных выше примеров документов.

0 голосов
/ 09 декабря 2018

Вы должны использовать $group пару раз здесь.Сначала с users и source и подсчитайте общее количество байтов, используя $sum.

И второй с users и $push source и bytes в массив

db.collection.aggregate([
  { "$unwind": "$users" },
  { "$group": {
    "_id": {
      "users": "$users",
      "source": "$remote.source"
    },
    "bytes": { "$sum": "$remote.bytes" }
  }},
  { "$group": {
    "_id": "$_id.users",
    "data": {
      "$push": {
        "source": "$_id.source",
        "bytes": "$bytes"
      }
    }
  }}
])

И даже если вы хотите преобразовать source и bytes в формат значения ключа, замените последний $group этап на два следующих этапа.

{ "$group": {
  "_id": "$_id.users",
  "data": {
    "$push": {
      "k": "$_id.source",
      "v": "$bytes"
    }
  }
}},
{ "$project": {
  "_id": 0,
  "username": "$_id",
  "bytes": { "$arrayToObject": "$data" }
}}
...