78 Stimmen

MongoDB: Aktualisieren von Dokumenten mit Daten aus demselben Dokument

Ich habe eine Liste von Dokumenten, jedes mit lat und lon Eigenschaften (neben anderen).

{ 'lat': 1, 'lon': 2, someotherdata [...] } 
{ 'lat': 4, 'lon': 1, someotherdata [...] }
[...]

Ich möchte sie so ändern, dass sie wie folgt aussieht:

{ 'coords': {'lat': 1, 'lon': 2}, someotherdata [...]} 
{ 'coords': {'lat': 4, 'lon': 1}, someotherdata [...]}
[...]

Bis jetzt habe ich das hier:

db.events.update({}, {$set : {'coords': {'lat': db.events.lat, 'lon': db.events.lon}}}, false, true)

Aber es behandelt die db.events.lat y db.events.lon als Zeichenketten. Wie kann ich auf die Eigenschaften des Dokuments verweisen?

乾杯

214voto

Niels van der Rest Punkte 30365

Aktualisierung: Wenn Sie nur die Struktur eines Dokuments ändern müssen, ohne die Werte zu ändern, siehe gipset's Antwort für eine gute Lösung.


Laut einem (inzwischen nicht mehr verfügbaren) Kommentar auf der Dokumentationsseite aktualisieren können Sie nicht auf die Eigenschaften des aktuellen Dokuments innerhalb einer update() .

Sie müssen alle Dokumente durchgehen und sie auf diese Weise aktualisieren:

db.events.find().snapshot().forEach(
  function (e) {
    // update document, using its own properties
    e.coords = { lat: e.lat, lon: e.lon };

    // remove old properties
    delete e.lat;
    delete e.lon;

    // save the updated document
    db.events.save(e);
  }
)

Eine solche Funktion kann auch in einem Map-Reduce-Job oder einer serverseitigen Anwendung verwendet werden db.eval() Job, je nach Ihren Bedürfnissen.

57voto

gipset Punkte 752

El $umbenennen Operator (der einen Monat, nachdem diese Frage gestellt wurde, eingeführt wurde) macht es wirklich einfach, diese Art von Dingen zu tun, bei denen Sie die Werte nicht ändern müssen.

Einige Testdokumente einfügen

db.events.insert({ 'lat': 1, 'lon': 2, someotherdata: [] })
db.events.insert({ 'lat': 4, 'lon': 1, someotherdata: [] })

verwenden Sie die $rename Betreiber

db.events.update({}, {$rename: {'lat': 'coords.lat', 'lon': 'coords.lon'}}, false, true)

Ergebnisse

db.events.find()
{
    "_id" : ObjectId("5113c82dd28c4e8b79971add"),
    "coords" : {
        "lat" : 1,
        "lon" : 2
    },
    "someotherdata" : [ ]
}
{
    "_id" : ObjectId("5113c82ed28c4e8b79971ade"),
    "coords" : {
        "lat" : 4,
        "lon" : 1
    },
    "someotherdata" : [ ]
}

6voto

mjwrazor Punkte 1608

Neils Antwort . Nur um die Leute wissen zu lassen, dass Sie dies nicht auf einer großen Datenbank ausführen können, wenn Sie es, sagen wir, per Remote Shell wie Robomongo machen. Sie müssen sich in die Mongo-Shell Ihres eigentlichen Servers einwählen. Sie könnten dies auch tun, wenn Sie lieber ein Update durchführen möchten.

db.Collection.find({***/ possible query /***}).toArray().forEach(
  function(obj){
    obj.item = obj.copiedItem;
    obj.otherItem = obj.copiedItem;
    obj.thirdItem = true;
    obj.fourthItem = "string";
    db.Collection.update({_id: obj._id}, obj);
  }
);

3voto

Adam Comerford Punkte 20863

Solange Sie mit der Erstellung einer Kopie der Daten einverstanden sind, kann das Aggregations-Framework hier als Alternative verwendet werden. Sie haben auch die Möglichkeit, mehr mit den Daten zu machen, wenn Sie andere Operatoren verwenden möchten, aber der einzige, den Sie brauchen, ist $project . Das ist zwar etwas platzraubend, kann aber schneller sein und ist für manche Zwecke besser geeignet. Zur Veranschaulichung füge ich zunächst einige Beispieldaten in die Datei foo Sammlung:

db.foo.insert({ 'lat': 1, 'lon': 2, someotherdata : [1, 2, 3] })
db.foo.insert({ 'lat': 4, 'lon': 1, someotherdata : [4, 5, 6] })

Jetzt verwenden wir einfach $project zur Überarbeitung der lat y lon Felder, und senden Sie sie dann an die newfoo Sammlung:

db.foo.aggregate([
    {$project : {_id : "$_id", "coords.lat" : "$lat", "coords.lon" : "$lon", "someotherdata" : "$someotherdata" }},
    { $out : "newfoo" }
])

Dann prüfen Sie newfoo für unsere veränderten Daten:

db.newfoo.find()
{ "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } }
{ "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } }

Wenn Sie mit den neuen Daten zufrieden sind, können Sie die Funktion renameCollection() um die alten Daten zu löschen und die neuen Daten unter dem alten Namen zu verwenden:

> db.newfoo.renameCollection("foo", true)
{ "ok" : 1 }
> db.foo.find()
{ "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } }
{ "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } }

Ein letzter Hinweis - bis SERVER-7944 abgeschlossen ist, können Sie nicht das Äquivalent eines Schnappschusses machen, indem Sie den Hinweis auf die _id Index wie vorgeschlagen in diese Antwort und so kann es passieren, dass Sie ein Dokument mehr als einmal treffen, wenn es durch eine andere Aktivität verschoben wird. Da Sie die _id Feld in diesem Beispiel würde jedes derartige Vorkommen zu einer Verletzung des eindeutigen Schlüssels führen, so dass Sie zwar keine Duplikate erhalten, aber möglicherweise eine "alte" Version eines Dokuments. Wie immer sollten Sie Ihre Daten gründlich überprüfen, bevor Sie sie löschen, und vorzugsweise eine Sicherungskopie erstellen.

3voto

Dac Nguyen Punkte 67

Wir können Mongo-Skripte verwenden, um Daten im laufenden Betrieb zu bearbeiten. Das funktioniert bei mir!

Ich verwende dieses Skript, um meine Adressdaten zu korrigieren.

Beispiel für eine aktuelle Adresse: "Nr. 12, FIFTH AVENUE,".

Ich möchte das letzte überflüssige Komma entfernen, die erwartete neue Adresse "No.12, FIFTH AVENUE".

var cursor = db.myCollection.find().limit(100);

while (cursor.hasNext()) {
  var currentDocument = cursor.next();

  var address = currentDocument['address'];
  var lastPosition = address.length - 1;

  var lastChar = address.charAt(lastPosition);

  if (lastChar == ",") {

    var newAddress = address.slice(0, lastPosition);

    currentDocument['address'] = newAddress;

    db.localbizs.update({_id: currentDocument._id}, currentDocument);

  }
}

Ich hoffe, das hilft!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X