Как фильтровать и агрегировать данные из одной коллекции в другой формат с помощью MongoDB

#mongodb #mongodb-query #aggregation-framework

#mongodb #mongodb-запрос #aggregation-framework

Вопрос:

У меня есть одна коллекция с именем ‘ctrlcharts’. например

 {  
   "_id" : ObjectId("57fc695492af567031246736"),
   "deviceId" : "A001",
   "sensorId" : "S003",
   "time" : "2016/10/11 12:23:50",
   "charts" : [ 
      {
        "sensor" : "ch_11",
        "value" : 120
      },
      {
        "sensor" : "ch_12",
        "value" : 150
      }
    ]
}
  

Как фильтровать "sensor" : "ch_11" и агрегировать данные из одной коллекции в другой формат с помощью MongoDB

например

 {         
   "time" : "2016/10/11 12:23:50",
   "sensor" : "ch_12",
   "value" : 150       
}
  

Я попробовал приведенный ниже код

 db.ctrlcharts.aggregate([
    { $match: {"deviceId" : "A001", "sensorId" : "S003", "time" : "2016/10/11 12:23:50"}},
    { $project: { 
        _id: 0,
        time : 1 , 
        sensor : "$charts.sensor"
        value : "$charts.value"
      }
    } 
])
  

Но я получил результат в виде

 {         
   "time" : "2016/10/11 12:23:50",
   "sensor" : ["ch_11","ch_12"],
   "value" : [120,150]
}
  

Спасибо

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

1. что вы пробовали?

Ответ №1:

Вы старались изо всех сил ….просто используйте $unwind

 db.ctrlcharts.aggregate(
{$unwind:"$charts"},
{$match: {"deviceId" :"A001", "charts.sensor":"ch_12", "time" : "2016/10/11 12:23:50"}},
{$project:{_id:0,time:1, sensor : "$charts.sensor", value :"$charts.value"}}).pretty()
  

Ответ №2:

Вы можете использовать $unwind (aggregation) для разделения массива диаграмм.

 db.ctrlcharts.aggregate( [ { $unwind : "$charts" } ] )
  

Это приведет к результату, подобному —

 { "_id" : ObjectId("57ff397a007c43ecacf10512"), "deviceId" : "A001", "sensorId" : "S003", "time" : "2016/10/11 12:23:50", "charts" : { "sensor" : "ch_11", "value" : 120 } }
{ "_id" : ObjectId("57ff397a007c43ecacf10512"), "deviceId" : "A001", "sensorId" : "S003", "time" : "2016/10/11 12:23:50", "charts" : { "sensor" : "ch_12", "value" : 150 } }
  

а затем используйте запрос соответствия

Ответ №3:

Используйте операторы $arrayElemAt and $filter для более эффективного запроса массива без необходимости $unwind . Причина $unwind , по которой это не так эффективно, заключается в том, что он создает декартово произведение документов, т.Е. Копию каждого документа на запись массива, что использует больше памяти (возможный объем памяти на конвейерах агрегации составляет 10% от общей памяти) и, следовательно, требует времени для создания, а также обработки документов в процессе выравнивания.

$filter Вернет подмножество массива, которое содержит только элементы, соответствующие условию фильтра. Затем $arrayElemAt оператор возвращает элемент из отфильтрованного массива с указанным индексом массива, чтобы предоставить вам нужный вам вложенный документ.

Необходимо еще $project сгладить поля, чтобы получить желаемый результат:

 db.ctrlcharts.aggregate([
    { "$match": { 
        "deviceId": "A001", 
        "sensorId": "S003", 
        "time": "2016/10/11 12:23:50",
        "charts.sensor": "ch_11"
    } },
    { 
        "$project": { 
            "time": 1, 
            "chart": {
                "$arrayElemAt": [
                    "$filter": {
                        "input": "$charts",
                        "as": "item",
                        "cond": { "$eq": ["$$item.sensor", "ch_11"] }
                    }, 0
                ]
            }
        }
    },
    { 
        "$project": { 
            "_id": 0,
            "time": 1, 
            "sensor": "$chart.sensor"
            "value": "$chart.value"
        }
    } 
])