монго — счетчик возвращает документ, не найденный вместо 0

#mongodb

Вопрос:

В SQL-запросе

 select count(*) from table where id=1
 

вернул 0 бы результат, если бы не было никакой записи с таким идентификатором.

Я хотел бы получить точно такое же поведение, но в монго. К сожалению, я могу использовать только агрегатную функцию.

Я пытался сделать что-то вроде этого

 db.collection.aggregate([
  {
    "$match": {
      "key": 1
    }
  },
  {
    $count: "s"
  }
])
 

Он работает, но только с записями key:1 , но когда этот ключ не существует, «документ не найден».

Ответ №1:

Вы можете использовать этот запрос агрегации, используя $facet для создания двух возможных способов: если документ существует или если документ не существует.

  • Сначала $facet нужно создать два способа
  • В notFound пути результат всегда будет {count: 0} ; в found пути есть match
  • Затем $replaceRoot объедините результаты, чтобы получить желаемое значение.
 db.collection.aggregate([
  {
    "$facet": {
      "notFound": [
        {
          "$project": {
            "_id": 0,
            "count": {
              "$const": 0
            }
          }
        },
        {
          "$limit": 1
        }
      ],
      "found": [
        {
          "$match": {
            "key": 1
          }
        },
        {
          "$count": "count"
        }
      ]
    }
  },
  {
    "$replaceRoot": {
      "newRoot": {
        "$mergeObjects": [
          {
            "$arrayElemAt": [
              "$notFound",
              0
            ]
          },
          {
            "$arrayElemAt": [
              "$found",
              0
            ]
          }
        ]
      }
    }
  }
])
 

Пример здесь, где ключ существует, и здесь, где ключа не существует.

Также я протестировал это с помощью $ifNull вместо $mergeObjects и, похоже, тоже работает нормально.

Комментарии:

1. Большое вам спасибо, все работает именно так, как я и ожидал.

Ответ №2:

Я думаю, что правильный способ сделать это-с кодом драйвера, если вы получите пустые результаты, вы сделаете этот документ {"count" : 0} , который вам не нужен, я думаю, чтобы что-то сделать в базе данных.

Другим решением может быть следующее (замените 5 значением ключа, которое вы хотите)

Тестовый код здесь

  • создает 2 группы matched(count>0) » и » не matched(count=0)
  • Сортировать по {"count" : -1}
  • возьмите first , если было совпадение, количество совпадений будет одинаковым, иначе оно будет равно 0
 aggregate(
[ {
  "$group" : {
    "_id" : {
      "$cond" : [ {"$eq" : [ "$key", 5 ]}, "$key", "not_match" ]
    },
    "count" : {
      "$sum" : {"$cond" : [ {"$eq" : [ "$key", 5 ]}, 1, 0 ]}
    }
  }
 }, 
 {"$sort" : {"count" : -1}},
 {
  "$group" : {
    "_id" : null,
    "count" : {"$first" : "$count"}
  }
 },
 {"$project" : {"_id" : 0}}
])