MongoDB: добавить поле с условным количеством элементов - PullRequest
1 голос
/ 13 июля 2020

У меня следующая упрощенная коллекция

[
  {
    "key": 1,
    "array": [
      {        "check": true      },
      {        "check": false      },
      {        "check": true      }
    ]
  },
  {
    "key": 2
  }
]

Я хочу добавить поле «count» с количеством элементов массива с «check» = true, поэтому я ожидаю следующий результат

  {
    "key": 1,
    "array": [
      {        "check": true      },
      {        "check": false      },
      {        "check": true      }
    ],
    "count":2,
  },
  {
    "key": 2,
    "count": 0
  }
]

У меня следующий запрос (это агрегация, потому что на самом деле это один из этапов конвейера)

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          "$cond": {
            "if": {
              "$eq": ["$array.check",true],              
            },
            "then": 1,
            "else": 0,            
          }
        }
      },      
    }
  }
])

Но я всегда получаю count = 0.

Можете ли вы помочь мне найти ошибку в моем запросе?

Здесь пн go площадка

Ответы [ 3 ]

2 голосов
/ 13 июля 2020

Вместо использования $sum вы можете использовать $filter для фильтрации только массива с помощью "check"=true, а затем проверить размер результирующего массива с помощью $size .

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$size": {
          "$filter": {
            "input": { "$ifNull": ["$array", []] }, // default empty array if array is does not exist
            "cond": "$$this.check" // only keep the truthy check value
          }
        }
      }
    }
  }
])

Пн go Игровая площадка

В качестве альтернативы, если вы хотите использовать $sum, вы также можете сопоставить массив с массивом 0 и 1 согласно значению check, используя $map

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          "$map": {
            "input": { "$ifNull": ["$array", []] },
            "in": {
              "$cond": ["$$this.check", 1, 0]
            }
          }
        }
      }
    }
  }
])

Пн go Детская площадка

1 голос
/ 13 июля 2020

Вот как этого добиться, используя $ уменьшить

db.collection.aggregate([
  {
    "$addFields": {
      "count": {
        "$sum": {
          $reduce: {
            input: "$array",
            initialValue: 0,
            in: {
              $sum: [
                "$$value",
                {
                  $cond: [
                    "$$this.check",
                    1,
                    0
                  ]
                }
              ]
            }
          }
        }
      }
    }
  }
])

Пн go Игровая площадка

0 голосов
/ 13 июля 2020

Используя $reduce оператор выражения массива агрегации,

db.test.aggregate( [
  { 
      $addFields: { 
          count: { 
              $reduce: { 
                  input: { $ifNull: [ "$array", [] ] }, 
                  initialValue: 0, 
                  in: { 
                      $cond: [ { $eq: [ "$$this.check", true ] }, 
                               { $add: [ "$$value", 1 ] }, 
                               "$$value" 
                      ] 
                  }
              }
          }
      }
  }
] )

получает следующий результат:

{
        "_id" : ObjectId("5f0c7b691c7c98bb49fd2b50"),
        "key" : 1,
        "array" : [
                {
                        "check" : true
                },
                {
                        "check" : false
                },
                {
                        "check" : true
                }
        ],
        "count" : 2
}
{ "_id" : ObjectId("5f0c7b691c7c98bb49fd2b51"), "key" : 2, "count" : 0 }
...