2016-05-04 5 views
1

Unsere Projektdatenbank hat eine Capped-Sammlung namens Werte, die alle paar Minuten mit neuen Daten von Sensoren aktualisiert wird. Diese Sensoren gehören alle zu einem einzigen Sensorknoten, und ich möchte die letzten Daten von diesen Knoten in einer einzigen Aggregation abfragen. Das Problem, das ich habe, filtert nur den letzten aller Arten von Sensoren aus, während es immer noch nur eine (effiziente) Abfrage gibt. Ich habe mich umgesehen und das Argument $ group gefunden, aber ich kann mir nicht vorstellen, wie man es in diesem Fall richtig benutzt.MongoDB filtert Filialdokumente mit Lookup-Aggregation

Die Datenbank ist wie folgt strukturiert:

Knoten:

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

Werte:

{ 
    "_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 
} 

so stellen wir uns vor ich die Daten vom Knoten 681, möchte ich wie eine Struktur wollen dies:

Knoten:

{ 
    "_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 
      } 
    ] 
} 

Beachten Sie, wie ein Wert von foo nicht abgefragt wird, weil ich nur den letzten Wert erhalten möchte, wenn es mehr als einen Wert gibt (was immer der Fall sein wird). Die Reihenfolge der Sammlung entspricht bereits dem Zeitstempel, da die Sammlung begrenzt ist.

Ich habe diese Abfrage, aber es bekommt nur alle Werte aus der Datenbank (was waaay zu viel im Leben zu tun ist, geschweige denn eine Anfrage der Web-App), also habe ich mich gefragt, wie ich es filtern würde vor wird es aggregiert.

query:

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

Antwort

0

soweit ich Dokumentstruktur erhalten, gibt es keine Notwendigkeit $ Suche verwendet werden, da alle Daten in Lesungen (Wert) Sammlung.

Bitte vorgeschlagene Lösung sehen:

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" 
        } 
       } 
      } 
     } 

    ]) 

und Ausgang:

{ 
    "_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" 
     } 
    ] 
} 

Alle Kommentare willkommen!

+0

Sie mein Herr mein Tag, diese Abfrage ist sehr viel, was ich suchte. Vielen Dank. –

1

Versuchen Sie, diese

// 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"} 
     } 
    } 

    ]