2016-05-04 3 views
1

Наша база данных проекта имеет ограниченную коллекцию, называемую значениями, которая каждые несколько минут обновляется новыми данными с датчиков. Все эти датчики принадлежат одному узлу датчика, и я хотел бы запросить последние данные из этих узлов в одной совокупности. Проблема, с которой я столкнулась, заключается в фильтрации только последнего из ВСЕХ типов датчиков, в то же время имеющих только один (эффективный) запрос. Я огляделся и нашел аргумент $ group, но я не могу понять, как правильно использовать его в этом случае.MongoDB отфильтровывает поддокументы с агрегированием поиска

База данных структурирована следующим образом:

узлы:

{ 
    "_id": 681 
    "sensors": [ 
      { 
       "type": "foo" 
      }, 
      { 
       "type": "bar" 
      } 
    ] 
} 

значения:

{ 
    "_id" : ObjectId("570cc8b6ac55850d5740784e"), 
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
    "type" : "foo", 
    "nodeid" : 681, 
    "value" : 10 
} 

{ 
    "_id" : ObjectId("190ac8b6ac55850d5740776e"), 
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
    "type" : "bar", 
    "nodeid" : 681, 
    "value" : 20 
} 

{ 
    "_id" : ObjectId("167bc997bb66750d5740665e"), 
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
    "type" : "bar", 
    "nodeid" : 200, 
    "value" : 20 
} 

{ 
    "_id" : ObjectId("110cc9c6ac55850d5740784e"), 
    "timestamp" : ISODate("2016-04-09T12:06:46.344Z"), 
    "type" : "foo", 
    "nodeid" : 681, 
    "value" : 12 
} 

так давайте представим, я хочу, чтобы данные из узла 681, я хотел бы структуру, подобную это:

Узлы:

{ 
    "_id": 681 
    "sensors": [ 
      { 
       "_id" : ObjectId("570cc8b6ac55850d5740784e"), 
       "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
       "type" : "foo", 
       "nodeid" : 681, 
       "value" : 10 
      }, 
      { 
       "_id" : ObjectId("190ac8b6ac55850d5740776e"), 
       "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
       "type" : "bar", 
       "nodeid" : 681, 
       "value" : 20 
      } 
    ] 
} 

Обратите внимание, что одно значение foo не запрашивается, потому что я хочу получить только самое последнее значение, если имеется более одного значения (что всегда будет иметь место). Заказ коллекции уже соответствует временной отметке, потому что коллекция ограничена.

У меня есть этот запрос, но он просто получает все значения из базы данных (что слишком много для жизни, не говоря уже о одном запросе веб-приложения), поэтому мне было интересно, как я буду фильтровать его до он объединяется.

запрос:

db.nodes.aggregate(
     [ 
      { 
       $unwind: "$sensors" 
      }, 
      { 
       $match:{ 
        nodeid: 681 
         } 
      }, 
      { 
       $lookup:{ 
         from: "values", localField: "sensors.type", foreignField: "type", as: "sensors" 
        } 
      } 
     } 
    ] 
) 

ответ

0

насколько я получил структуру документа, нет необходимости использовать $ поиск, как все данные в чтениях (значения) коллекции.

Пожалуйста, смотрите предложенное решение:

db.readings.aggregate([{ 
      $match : { 
       nodeid : 681 
      } 
     }, 
     { 
      $group : { 
       _id : { 
        type : "$type", 
        nodeid : "$nodeid" 
       }, 
       readings : { 
        $push : { 
         timestamp : "$timestamp", 
         value : "$value", 
         id : "$_id" 
        } 
       } 
      } 
     }, { 
      $project : { 
       _id : "$_id", 
       readings : { 
        $slice : ["$readings", -1] 
       } 
      } 
     }, { 
      $unwind : "$readings" 
     }, { 
      $project : { 
       _id : "$readings.id", 
       type : "$_id.type", 
       nodeid : "$_id.nodeid", 
       timestamp : "$readings.timestamp", 
       value : "$readings.value", 

      } 
     }, { 
      $group : { 
       _id : "$nodeid", 
       sensors : { 
        $push : { 
         _id : "$_id", 
         timestamp : "$timestamp", 
         value : "$value", 
         type:"$type" 
        } 
       } 
      } 
     } 

    ]) 

и выход:

{ 
    "_id" : 681, 
    "sensors" : [ 
     { 
      "_id" : ObjectId("110cc9c6ac55850d5740784e"), 
      "timestamp" : ISODate("2016-04-09T12:06:46.344Z"), 
      "value" : 12, 
      "type" : "foo" 
     }, 
     { 
      "_id" : ObjectId("190ac8b6ac55850d5740776e"), 
      "timestamp" : ISODate("2016-04-12T12:06:46.344Z"), 
      "value" : 20, 
      "type" : "bar" 
     } 
    ] 
} 

Любые комментарии приветствуются!

+0

Вам сударь мой сделал мой день, этот вопрос очень много, что я искал. Огромное спасибо. –

1

Попробуйте

// Pipeline 
    [ 
    // Stage 1 - sort the data collection if not already done (optional) 
    { 
     $sort: { 
     "timestamp":1 
     } 
    }, 

    // Stage 2 - group by type & nodeid then get first item found in each group 
    { 
     $group: { 
     "_id":{type:"$type",nodeid:"$nodeid"}, 
     "sensors": {"$first":"$$CURRENT"} //consider using $last if your collection is on reverse 
     } 
    }, 

    // Stage 3 - project the fields in desired 
    { 
     $project: { 
     "_id":"$sensors._id", 
     "timestamp":"$sensors.timestamp", 
     "type":"$sensors.type", 
     "nodeid":"$sensors.nodeid", 
     "value":"$sensors.value" 
     } 

    }, 

    // Stage 4 - group and push it to array sensors 
    { 
     $group: { 
     "_id":{nodeid:"$nodeid"}, 
     "sensors": {"$addToSet":"$$CURRENT"} 
     } 
    } 

    ] 
Смежные вопросы