2017-06-28 14 views
1

Ich erstelle ein "Simulationsprogramm", wo ich Positionen von etwa 700 beweglichen Objekten in einer MongoDB speichern kann. Ich speichere alle Positionen in einer Sammlung und jedes Dokument ist ein "Moving Object". So weit wie gut.Finde das nächste Spiel von Array

Nun mein Problem: Ich mag würde alle positons von den 700 „Objekte“ mit einer Abfrage, aber die Zeitstempel der Positionen lesen sind variabel ...

Beispieldokument:

{ 
    "_id" : ObjectId("59522479707c4fbf16b2f91b"), 
    "PuckId" : 0, 
    "Positions" : [ 
     { 
      "time" : 0, 
      "x_pos" : 0, 
      "y_pos" : 0, 
      "state" : 1 
     }, 
     { 
      "time" : 10, 
      "x_pos" : 5, 
      "y_pos" : 5, 
      "state" : 1 
     }, 
     { 
      "time" : 20, 
      "x_pos" : 0, 
      "y_pos" : 20, 
      "state" : 1 
     }, 
     { 
      "time" : 25, 
      "x_pos" : 5, 
      "y_pos" : 10, 
      "state" : 1 
     } 
    ] 
} 
{ 
    "_id" : ObjectId("59522660707c4fbf16b38701"), 
    "PuckId" : 1, 
    "Positions" : [ 
     { 
      "time" : 1, 
      "x_pos" : 1, 
      "y_pos" : 0, 
      "state" : 1 
     }, 
     { 
      "time" : 5, 
      "x_pos" : 5, 
      "y_pos" : 10, 
      "state" : 1 
     }, 
     { 
      "time" : 8, 
      "x_pos" : 0, 
      "y_pos" : 2, 
      "state" : 1 
     }, 
     { 
      "time" : 22, 
      "x_pos" : 5, 
      "y_pos" : 0, 
      "state" : 1 
     } 
    ] 
} 

Hier ist, was ich bisher habe: (Für dieses Beispiel ich versuche, die Positon des Objekts bei Timesamp 10 abzufragen)

db.getCollection('LogFileV2').aggregate([ 
    { 
     $project: { 
      Positions:{ 
       $filter: { 
        input: "$Positions",  //{$slice: ["$Positions",1]}, *see below 
        as: "pos", 

        cond: { 
         $or: [{ 
          $lt: ["$$pos.time", 10+1] //at Timestamp 10 
         }] 
        } 
       } 
      } 
     } 
    } 
]); 
  • Wenn ich $ slice an dieser Position verwende, gibt es nur die Position FIRST zurück. Aber ich brauche nur die letzte Position, die von dem Zeitstempel (hier 10) abhängt, den ich betrete.

Also, was muss ich dieses Ergebnis zu erhalten, ändern:

/* 1 */ 
{ 
    "_id" : ObjectId("59522479707c4fbf16b2f91b"), 
    "Positions" : [ 
     { 
      "time" : 10, 
      "x_pos" : 5, 
      "y_pos" : 5, 
      "state" : 1 
     } 
    ] 
} 
/* 2 */ 
{ 
    "_id" : ObjectId("59522660707c4fbf16b38701"), 
    "Positions" : [ 
     { 
      "time" : 8, 
      "x_pos" : 0, 
      "y_pos" : 2, 
      "state" : 1 
     } 
    ] 
} 
+0

Ich habe ein anderes Dokument hinzugefügt. Jetzt sehen Sie wahrscheinlich, dass die Zeitstempel nicht gleich sind und ich kann nicht nach 10 suchen und das ist es. Wenn ein Dokument keine Zeit 10 hat, sollte es den nächsten anderen Array-Eintrag zurückgeben. – noscript

+0

Ja, da muss ich die genaue Position aller Objekte zu einem bestimmten Zeitpunkt wissen. Und es gibt keine Option, um den richtigen Zeitstempel zu erhalten, um das Ergebnis zu erhalten. – noscript

+0

Entschuldigung für die Verwirrung. Ich war noch nicht fertig, und es gibt eine schnellere Variante, solange Ihre MongoDB dies unterstützt. –

Antwort

0

Für die nächste ich so etwas wie diese verwenden würde:

db.getCollection('LogFileV2').aggregate([ 
    { "$match": { "Positions.time": { "$lte": 10 } } }, 
    { "$project": { 
    "Positions": { 
     "$map": { 
     "input": { 
      "$filter": { 
      "input": "$Positions", 
      "as": "pos", 
      "cond": { "$lte": [ "$$pos.time", 10 ] } 
      } 
     }, 
     "as": "pos", 
     "in": { 
      "time": "$$pos.time", 
      "x_pos": "$$pos.x_pos", 
      "y_pos": "$$pos.y_pos", 
      "state": "$$pos.state", 
      "diff": { "$subtract": [ 10, "$$pos.time" ] } 
     } 
     } 
    } 
    }}, 
    { "$unwind": "$Positions" }, 
    { "$sort": { "_id": 1, "Positions.diff": 1 } }, 
    { "$group": { 
    "_id": "$_id", 
    "Positions": { "$first": "$Positions" } 
    }}, 
    { "$sort": { "_id": 1 } } 
]) 

Welche gibt Ihnen:

/* 1 */ 
{ 
    "_id" : ObjectId("59522479707c4fbf16b2f91b"), 
    "Positions" : { 
     "time" : 10.0, 
     "x_pos" : 5.0, 
     "y_pos" : 5.0, 
     "state" : 1.0, 
     "diff" : 0.0 
    } 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("59522660707c4fbf16b38701"), 
    "Positions" : { 
     "time" : 8.0, 
     "x_pos" : 0.0, 
     "y_pos" : 2.0, 
     "state" : 1.0, 
     "diff" : 2.0 
    } 
} 

Also die grundlegende Änderung dort abgesehen von der Abfrage, um die Dokumente t zu beseitigen Hut die Bedingung nicht erfüllen, ist die Verwendung von $map, um die "Differenz" von dem abgefragten Wert zu erhalten.

Dann wollen wir im Grunde $sort die Array-Ergebnisse und nur diejenige, die den geringsten Unterschied hatte. Dies erhalten Sie über mit einer $group Pipelinestufe.

Alternativ könnten Sie das Array innerhalb $let und $filter wieder gegen den $min Wert definieren. Dies wäre schneller wo unterstützt:

db.getCollection('LogFileV2').aggregate([ 
    { "$match": { "Positions.time": { "$lte": 10 } } }, 
    { "$project": { 
    "Positions": { 
     "$let": { 
     "vars": { 
      "filtered": { 
      "$map": { 
       "input": { 
       "$filter": { 
        "input": "$Positions", 
        "as": "pos", 
        "cond": { "$lte": [ "$$pos.time", 10 ] } 
       } 
       }, 
       "as": "pos", 
       "in": { 
       "time": "$$pos.time", 
       "x_pos": "$$pos.x_pos", 
       "y_pos": "$$pos.y_pos", 
       "state": "$$pos.state", 
       "diff": { "$subtract": [ 10, "$$pos.time" ] } 
       } 
      } 
      } 
     }, 
     "in": { 
      "$arrayElemAt": [ 
      { "$filter": { 
       "input": "$$filtered", 
       "as": "f", 
       "cond": { "$eq": [ "$$f.diff", { "$min": "$$filtered.diff" } ] } 
      }}, 
      0 
      ] 
     } 
     } 
    } 
    }} 
]) 
Verwandte Themen