Frage

Jeden Tag erhalte ich einen Vorrat von Dokumenten (Update). Was ich tun möchte, ist Einsatz jedes Element, das nicht bereits vorhanden ist.

  • Ich mag auch den Überblick über die erste Zeit halten wir sie eingeführt wird, und das letzte Mal, als ich sah, wie sie in einem Update.
  • Ich möchte nicht, doppelte Dokumente haben.
  • Ich will nicht, um ein Dokument entfernen, die zuvor gespeicherten wurde, aber nicht in meinem Update.
  • 95% (geschätzt) die Aufzeichnungen von Tag zu Tag unmodifizierten sind.

Ich bin mit dem Python-Treiber (pymongo).

Was ich momentan tun ist (Pseudo-Code):

for each document in update:
      existing_document = collection.find_one(document)
      if not existing_document:
           document['insertion_date'] = now
      else:
           document = existing_document
      document['last_update_date'] = now
      my_collection.save(document)

Mein Problem ist, dass es sehr langsam ist (40 Minuten für weniger als 100 000 Datensätze, und ich habe Millionen von ihnen in dem Update). Ich bin ziemlich sicher, dass es etwas gibt, builtin, dies zu tun, aber das Dokument für update () ist mmmhhh .... ein bisschen kurz und bündig .... ( http://www.mongodb.org/display/DOCS/Updating )

Kann jemand raten, wie es schneller machen?

War es hilfreich?

Lösung

Sounds, wie Sie eine „Upsert“ machen wollen. MongoDB hat eine eingebaute Unterstützung für diese. Führen Sie einen zusätzlichen Parameter zu Ihrem Update () -Aufruf: {Upsert: true}. Zum Beispiel:

key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument

Dies ersetzt Ihren if-Fund-else-Aktualisierungsblock vollständig. Es wird ein, wenn der Schlüssel nicht vorhanden und wird aktualisiert, wenn es der Fall ist.

Bevor:

{"key":"value", "key2":"Ohai."}

Nach:

{"key":"value", "key2":"value2", "key3":"value3"}

Sie können auch angeben, welche Daten Sie schreiben wollen:

data = {"$set":{"key2":"value2"}}

Ihre ausgewählte Dokument wird den Wert von „key2“ nur aktualisieren und lassen alles andere unberührt.

Andere Tipps

Wie von MongoDB 2.4, können Sie $ setOnInsert verwenden ( http: // docs. mongodb.org/manual/reference/operator/setOnInsert/ )

Set 'insertion_date' $ setOnInsert verwenden und 'last_update_date' mit $ Satz in Ihrem Upsert Befehl.

Um die Pseudo-Code in ein Arbeitsbeispiel drehen:

now = datetime.utcnow()
for document in update:
    collection.update_one(
        {"_id": document["_id"]},
        {
            "$setOnInsert": {"insertion_date": now},
            "$set": {"last_update_date": now},
        },
        upsert=True,
    )

Sie können immer einen eindeutigen Index machen, die MongoDB speichern eine widersprüchliche abzulehnen verursacht. Betrachten Sie das folgende getan, um die mongodb-Shell:

> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13})      # This works
> db.getCollection("test").insert({a:1, b:12, c:13})      # This fails
E11000 duplicate key error index: foo.test.$a_1  dup key: { : 1.0 }

Sie können Upsert mit $ setOnInsert Operator verwenden.

db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})

1. Verwenden Sie aktualisieren.

Zeichnung von Van Nguyen Antwort oben, benutzen Sie update statt speichern. Dadurch erhalten Sie Zugriff auf die Upsert Option.

Hinweis : Diese Methode überschreibt das gesamte Dokument, wenn gefunden ( der Dokumente )

var conditions = { name: 'borne' }   , update = { $inc: { visits: 1 }} , options = { multi: true };

Model.update(conditions, update, options, callback);

function callback (err, numAffected) {   // numAffected is the number of updated documents })

1.a. Verwenden $ set

Wenn Sie eine Auswahl des Dokuments aktualisieren mögen, aber nicht die ganze Sache, können Sie die $ set-Methode mit Update verwenden. (Wiederum Von der Dokumentation) ... Also, wenn Sie festlegen möchten ...

var query = { name: 'borne' };  Model.update(query, ***{ name: 'jason borne' }***, options, callback)

Senden Sie es als ...

Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)

Dies verhindert, dass versehentlich alle Ihre Vorlage (n) mit { name: 'jason borne' } überschrieben wird.

Ich glaube nicht, mongodb unterstützt diese Art der selektiven upserting. Ich habe das gleiche Problem wie LeMiz und mit update (Kriterien, NEWOBJ, Upsert, multi) rechts funktioniert nicht, wenn sowohl mit einem ‚erstellt‘ und ‚aktualisiert‘ Zeitstempel handelt. Angesichts der folgenden Upsert Anweisung:

update( { "name": "abc" }, 
        { $set: { "created": "2010-07-14 11:11:11", 
                  "updated": "2010-07-14 11:11:11" }},
        true, true ) 

Szenario 1 - Dokument mit ‚name‘ ‚abc‘ existiert nicht: Neues Dokument wird mit 'name' = 'abc', 'geschaffen' = 2010-07-14 11.11.11, und 'aktualisiert' = 2010-07-14 11.11.11 erstellt.

Szenario 2 - Dokument mit ‚name‘ ‚abc‘ existiert bereits mit dem folgenden: 'Name' = 'abc', 'geschaffen' = 2010-07-12 09.09.09, und 'aktualisiert' = 2010-07-13 10.10.10. Nach dem Upsert würde das Dokument jetzt das gleiche wie das Ergebnis in Szenario # 1 sein. Es gibt keine Möglichkeit, in einem Upsert angeben, welche Felder wenn das Einfügen festgelegt werden, und welche Felder allein, wenn die Aktualisierung gelassen werden.

Meine Lösung war einen eindeutigen Index für die critera Felder, führen Sie einen Einsatz zu schaffen, und unmittelbar danach ein Update nur auf dem ‚aktualisiert‘ Feld durchführen.

Zusammenfassung

  • Sie haben eine bestehende Sammlung von Datensätzen.
  • Sie haben einen Satz Datensätze, die Updates zu den bestehenden Datensätze enthalten.
  • Einige der Updates nicht wirklich etwas aktualisieren, sie duplizieren, was Sie haben bereits.
  • Alle Updates enthalten die gleichen Felder, die es bereits gibt, nur möglicherweise unterschiedliche Werte.
  • Sie verfolgen möchten, wenn ein Datensatz zuletzt geändert wurde, wobei ein Wert tatsächlich geändert.

Beachten Sie, ich bin Vermutung PyMongo, ändern Sie die Sprache der Wahl zu entsprechen.

Anleitung:

  1. Erstellen Sie die Sammlung mit einem Index mit einzigartigen = true, so dass Sie nicht doppelte Datensätze erhalten haben.

  2. Iterate über den Eingabedatensatz, Chargen von ihnen von 15.000 Datensätze erstellen oder so. Für jeden Datensatz in der Charge, erstellen Sie eine dict aus Daten, die Sie einfügen möchten, vorausgesetzt, jeder ein neuer Rekord sein wird. Fügen Sie die ‚erstellt‘ und ‚aktualisiert‘ Zeitstempel auf diese. Geben Sie diese als Batch-Insert-Befehl mit dem ‚ContinueOnError‘ flag = true, so dass der Einsatz von allem anderen auch passiert, wenn es einen doppelten Schlüssel drin (die es klingt wie es sein wird). DIES WIRD sehr schnell passiert. Bulk-Einsätze Rock, habe ich 15k / Sekunde Leistungsstufen bekommen. Weitere Hinweise zum ContinueOnError finden Sie unter http://docs.mongodb.org/manual/core/ Schreiboperationen /

    Nehmen Sie Einsätze passieren sehr schnell, so dass Sie mit diesen Einsätzen in kürzester Zeit durchgeführt werden. Nun ist es Zeit, die entsprechende Datensätze zu aktualisieren. Tun Sie dies mit einem Batch-Retrieval, viel schneller als einen nach dem anderen.

  3. Iterate über alle Ihre Eingabedatensätze wieder Chargen von 15K erstellen oder so. Auszug aus den Tasten (am besten, wenn es ein Schlüssel ist, aber kann nicht geholfen werden, wenn es nicht). Sie rufen dieses Bündel von Datensätzen aus Mongo mit einem db.collectionNameBlah.find ({field: {$ in: [1, 2,3 ...}) Abfrage. Für jede dieser Aufzeichnungen, festzustellen, ob ein Update da ist, und wenn ja, geben Sie das Update, einschließlich der Aktualisierung der ‚aktualisiert‘ Zeitstempel.

    Leider sollten wir beachten, MongoDB 2.4 und unten KEINE Bulk Update-Operation umfassen. Sie arbeiten daran, dass auf.

Key Optimierung Punkte:

  • Die Einsätze werden in beträchtlichem Ausmaß Ihre Operationen in der Masse beschleunigen.
  • Suchen Aufzeichnungen en masse werden die Dinge beschleunigen, zu.
  • Einzelne Updates sind der einzig mögliche Weg jetzt, aber 10gen arbeiten daran. Vermutlich wird dies in 2.6, obwohl ich bin mir nicht sicher, ob es bis dahin fertig werden, gibt es eine Menge Sachen zu tun ist (ich habe nach ihrem Jira-System).

Generell Update mit besser in MongoDB wie es wird nur das Dokument erstellen, wenn es noch nicht existiert, obwohl ich bin sicher, dass nicht, wie man Arbeit, die mit dem Python-Adapter.

Zweitens, wenn Sie nur, ob oder nicht wissen müssen, daß das Dokument vorhanden ist, count (), die Erträge nur eine Zahl eine bessere Option als find_one sein, die angeblich das ganze Dokument von Ihrem MongoDB verursachen unnötigen Datenverkehr übertragen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top