MongoDB совокупное количество возвратов документов или 0 - PullRequest
1 голос
/ 05 апреля 2020

У меня следующий агрегированный запрос:

db.user.aggregate()
    .match({"business_account_id" : ObjectId("5e3377bcb1dbae5124e4b6bf")})
    .lookup({
        'localField': 'profile_id',
        'from': 'profile',
        'foreignField' : '_id',
        'as': 'profile'
    })
    .unwind("$profile")
    .match({"profile.type" : "consultant"})
    .group({_id:"$business_account_id", count:{$sum:1}})

Моя цель - подсчитать, сколько пользователей консультантов принадлежат данной компании.

Используя приведенный выше запрос, если есть хотя бы один пользователь, принадлежащий указанному business_account_id, получает правильное значение счетчика.

Но если пользователей нет, .match({"business_account_id" : ObjectId("5e3377bcb1dbae5124e4b6bf")}) вернет пустой результат (0 документов).

Как я могу получить count: 0, если к компании не назначены пользователи?

Я пробовал много подходов, основанных на других потоках, но не могу получить count: 0

ОБНОВЛЕНИЕ 1

Простая версия моей проблемы:

коллекция пользователей

{
    "_id" : ObjectId("5e36beb7b1dbae5124e4b6dc"),
    "business_account_id" : ObjectId("5e3377bcb1dbae5124e4b6bf"),
},
{
    "_id" : ObjectId("5e36d83db1dbae5124e4b732"),
    "business_account_id" : ObjectId("5e3377bcb1dbae5124e4b6bf"),
}

Использование следующего агрегированного запроса:

db.getCollection("user").aggregate([
        { "$match" : { 
                "business_account_id" : ObjectId("5e3377bcb1dbae5124e4b6bf")
            }
        }, 
        { "$group" : { 
                "_id" : "$business_account_id", 
                "count" : { "$sum" : 1 }
            }
        }
]);

Я получаю:

{ 
    "_id" : ObjectId("5e3377bcb1dbae5124e4b6bf"), 
    "count" : 2
}

Но если я запрашиваю ObjectId, который не существует, например:

db.getCollection("user").aggregate([
        { "$match" : { 
                "business_account_id" : ObjectId("5e335c873e8d40676928656d")
            }
        }, 
        { "$group" : { 
                "_id" : "$business_account_id", 
                "count" : { "$sum" : 1 }
            }
        }
]);

, я получаю результат полностью пустым. Я ожидаю получить:

{ 
    "_id" : ObjectId("5e335c873e8d40676928656d"), 
    "count" : 0
}

Ответы [ 2 ]

2 голосов
/ 06 апреля 2020

Проблема root состоит в том, что если в коллекции user нет документа, удовлетворяющего начальному $match, то нечего передавать на следующую стадию конвейера. Если business_account_id действительно где-то существует (возможно, другая коллекция?), Запустите агрегацию для этой коллекции, чтобы при начальном совпадении был найден хотя бы один документ. Затем используйте $ lookup, чтобы найти пользователей. Если вы используете MongoDB 3.6+, вы можете объединить поиск пользователя и профиля. Наконец, используйте $size для подсчета элементов в массиве пользователей.

(вам, вероятно, потребуется настроить имена коллекций и полей)

db.businesses.aggregate([
    {$match:{_id : ObjectId("5e3377bcb1dbae5124e4b6bf")}},
    {$project: { _id:1 }},
    {$lookup:{
          from: "users",
          let: {"busId":"$_id"},
          as: "users",
          pipeline: [
               {$match: {$expr:{$eq:[
                                "$$busId",
                                "$business_account_id"
               ]}}},
               {$lookup:{
                    localField: "profile_id",
                    from: "profile",
                    foreignField : "_id",
                    as: "profile"
               }},
               {$match: { "profile.type" : "consultant"}}
          ]
     }},
     {$project: {
           _id: 0,
           business_account_id: "$_id",
           count:{$size:"$users"} 
     }}
])

Playground

2 голосов
/ 06 апреля 2020

Поскольку вы сопоставляете несуществующее значение business_account_id, процесс агрегации будет остановлен.

Обходной путь: Мы выполняем 2 агрегации параллельно с оператором $ facet , чтобы получить значение default, если сопоставление не дает результата.

Примечание: Убедитесь, что в коллекции user есть хотя бы 1 запись, иначе это не сработает

db.user.aggregate([
  {
    $facet: {
      not_found: [
        {
          $project: {
            "_id": ObjectId("5e3377bcb1dbae5124e4b6bf"),
            "count": { $const: 0 }
          }
        },
        {
          $limit: 1
        }
      ],
      found: [
        {
          "$match": {
            "business_account_id": ObjectId("5e3377bcb1dbae5124e4b6bf")
          }
        },
        {
          "$group": {
            "_id": "$business_account_id",
            "count": { "$sum": 1 }
          }
        }
      ]
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          {
            $arrayElemAt: ["$not_found", 0]
          },
          {
            $arrayElemAt: ["$found", 0]
          }
        ]
      }
    }
  }
])

MongoPlayground

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...