2010-06-28 6 views
5

Ich bin ein MongoDB-Neuling und wollte fragen, wie man einen Update-Befehl mit Upsert und Liste schreiben.MongoDB - Upsert mit Listen

Grundsätzlich möchte ich so etwas wie dies zu tun:

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
"some_other_data":"goes here", 
"trips": [ 
    {"name": "2010-05-10", 
    "loc": [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
     {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}] 
    }, 
    {"name": "2010-05-08", 
    "loc": [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
     {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
     {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
    } 
]} 

Beachten Sie, dass:

  • Sie liefern einen Ausflug Namen und den aktuellen Standort
  • Wird die Reise nicht bereits vorhanden ist, es muss erstellt werden
  • trips.name sollte eindeutig sein, so dass wenn es exis ts, Sie an die Standort-Array

anhängen Dies ist die Abfrage, die ich schrieb die Positionsoperator mit $ push kombinieren.

db.mycollection.update({"application_id": "MyTestApp", 
          "trips.name": "2010-05-10"}, 
          {$push: {'trips.$.loc': {"lat":11, "lng":11} }}, 
          true); 

Aber dies führt zu Daten wie folgt aus:

> db.mycollection.find({"application_id":"MyTestApp"})   
{ "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
"application_id" : "MyTestApp", 
"trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
"name" : "2010-05-10" } 
} 

Sie können sehen, dass

  • "Reisen" ist kein Array
  • es "$" wörtlich nahm und erstellt a Schlüssel damit (doh!)

Bisher war ich mit MongoDB ziemlich zufrieden, aber es gibt definitiv eine steile Lernkurve beim Schreiben komplizierter Abfragen.

Jede Rückmeldung wird geschätzt.

Vielen Dank im Voraus, Amie

+0

überprüfen meine Antwort unten wieder - ich habe es bearbeitet zu schließen, was ich glaube, dass die Lösung (oder zumindest etwas, das Sie sehr nahe kommen sollte) – nearlymonolith

+0

siehe dieses [SO Thread] (http://stackoverflow.com/questions/17994552/mongodb-update-documents-in-an-array/17995495#17995495). etwas ähnliches. – user10

Antwort

4

Sie können mische den Positionsoperator ("$") und einen Upsert; Das "$" wird während der Einfügung als Feldname behandelt. Sie können dies nicht für neue Dokumente tun, sondern nur für ein vorhandenes Dokument.

schlug ich eine Struktur mehr wie folgt aus:

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
"some_other_data":"goes here", 
"trips": { 
    "2010-05-10": 
     [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
     {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}], 
    "2010-05-08": 
     [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
     {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
     {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
    } 
} 

Dann sind Sie ein Update wie kann dieses Problem:

db.mycollection.update({application_id: "MyTestApp", "trips.2010-05-10":{$exists:true}}, 
         {$push: {"trips.2010-05-10": {lat:11, lng:11} }}, 
         true); 

Ergebnisse in diese eingeführt wird.

> db.mycollection.find() 
{ "_id" : ObjectId("4c2931d17b210000000045f0"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : [ { "lat" : 11, "lng" : 11 } ] } } 

und läuft es wieder geben Sie dies:

> db.mycollection.find() 
{ "_id" : ObjectId("4c2932db7b210000000045f2"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : 
     [ { "lat" : 11, "lng" : 11 }, 
      { "lat" : 11, "lng" : 11 } ] } } 
+0

Das ist sehr nah an dem, was ich versucht habe zu erreichen. Danke @ Scott Hernandez. Mit diesem Schema ist es möglich, eine Liste von Schlüsseln in den "Reisen" zu erhalten? ("2010-050-10", usw.) db.mycollection.find ({"application_id": "MytestApp"}, {"trips": true}) gibt den gesamten "trips" Hash zurück. – Grnbeagle

+0

Ich endete mit dieser Methode. Danke für die Lösung Scott! – Grnbeagle

+0

Das Problem dort ist, dass Sie nicht für etwas innerhalb einer Reise, wie Dokumente mit einer Reise bei Lat 21,321231 suchen können (wie Mongo (heute) hat keine Möglichkeit, "wild-card" Teil des Pfads zu dem Feld). – Nick

1

richtige Lösung EDITED

Das ist genau das Problem, das ich Mongo Hit Lernen gehören - Sie für den $addToSet Operator suchen (see docs here), dass mit dem verwendeten ist update Befehl, in Verbindung mit dem Positionsoperator $, den Sie verwendeten.

$ addToSet

{$ addToSet: {field: value}}

Fügt Wert auf das Array nur dann, wenn es nicht bereits in der Anordnung.

Die Abfrage wird somit (db.Stapel der Sammlung I für Testzwecke verwendet), Probelauf zu folgen:

db.stack.update({ "trips.name":"2010-05-10" }, 
       { $addToSet: { "trips.$.loc":{"lat":11, "lng":12} } } 
       ); 

TESTLAUF (mit einigen Abkürzungen für Raum der Elemente, die nicht wichtig sind):

#### YOUR ITEM IN THE DB 
> db.stack.find({"trips.name":"2010-05-10"}) 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
    { "name" : "2010-05-10", 
     "loc" : [ { 
       "lat" : 21.321231, 
       "lng" : 16.8783234, 
       "updated_at" : "Mon May 10 2010 15:24:35" 
      }, { "lat" : 21.321231, 
       "lng" : 16.8783234, 
       "updated_at" : "Mon May 10 2010 15:24:24" 
      } ] }, 
    { "name" : "2010-05-08", 
     "loc" : [ ... ] 
    } ] } 
#### SUCCESSFULLY ADDS ITEM TO PROPER ARRAY 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
     { "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
     } ] } 
#### ON REPEAT RUN DOESN'T ADD NEW ELEMENT 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ { 
      "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
     } ] } 
#### BUT WILL CORRECTLY ADD ANOTHER ELEMENT TO THE SAME ARRAY IF IT'S NOT PRESENT 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":12}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
     { "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       }, { "lat" : 11, 
        "lng" : 12 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
    } ] } 
+0

Danke für die Antwort @Anthony Morelli. Ich habe $ addToSet ausprobiert und musste upsert = true übergeben, um zum ersten Mal eine Reise einzufügen. Wenn ich den Namen der Reise in etwas anderes änderte, erstellt dies tatsächlich ein neues Dokument, anstatt das aktuelle Dokument zu verwenden. Wie können wir angeben, dass "Trips" ein Array ist? – Grnbeagle

+0

Welche Abfrage haben Sie speziell ausgeführt? $ addToSet funktioniert nur mit Arrays, daher glaube ich nicht, dass die Spezifikation das Problem ist. – nearlymonolith

+0

Ich habe Ihre Abfrage genau ausgeführt, und es hat kein Dokument erstellt, also habe ich upsert = true übergeben. Nachdem es das erste Dokument erstellt hat, wenn es zum zweiten Mal ausgeführt wurde, hat es ein zweites Dokument erstellt, anstatt es an das vorherige anzuhängen. – Grnbeagle