Pregunta

Cada día, recibo un depósito de documentos (una actualización). Lo que quiero hacer es insertar cada elemento que aún no existe.

  • También quiero hacer un seguimiento de la primera vez que los insertado, y la última vez que los vio en una actualización.
  • No quiero tener documentos duplicados.
  • No quiero para eliminar un documento que ha sido previamente guardada, pero no está en mi actualización.
  • 95% (estimado) de los registros son no modificada de día en día.

Estoy utilizando el controlador de Python (pymongo).

Lo que actualmente hago es (pseudo-código):

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)

Mi problema es que es muy lenta (40 minutos para menos de 100 000 registros, y tengo millones de ellos en la actualización). Estoy bastante seguro de que hay algo incorporado para hacer esto, pero el documento de actualización () es mmmhhh .... un poco escueta .... ( http://www.mongodb.org/display/DOCS/Updating )

Puede alguien aconsejar cómo hacerlo más rápido?

¿Fue útil?

Solución

Parece que usted quiere hacer una "upsert". MongoDB ha incorporado en el apoyo a esta. Pasar un parámetro adicional a su llamada de actualización (): {upsert: true}. Por ejemplo:

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

Esto reemplaza el bloque si-hallazgo-otro-actualización del todo. Se insertará si no existe la clave y se actualizará si lo hace.

Antes:

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

Después de:

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

También puede especificar los datos que desea escribir:

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

Ahora el documento seleccionado se actualizará el valor de "clave2" solamente y dejar todo lo demás intacto.

Otros consejos

A partir de MongoDB 2.4, puede utilizar $ setOnInsert ( http: // docs. mongodb.org/manual/reference/operator/setOnInsert/ )

Set 'insertion_date' usando $ setOnInsert y 'LAST_UPDATE_DATE' usando $ set en su comando upsert.

Para encender el pseudocódigo en un ejemplo de trabajo:

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

Siempre se puede hacer un índice único, lo que provoca MongoDB para rechazar una conflictiva Guardar. Consideremos el siguiente hecho usando el shell mongodb:

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

Se puede utilizar con Upsert $ setOnInsert operador.

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

1. Uso de actualización.

A partir de la respuesta de Van Nguyen anterior, actualizar uso en lugar de Guardar. Esto le da acceso a la opción upsert.

Nota: : Este método, se sustituye todo el documento cuando se encuentran ( De los documentos )

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. Uso $ estableció

Si desea actualizar una selección del documento, pero no todo el asunto, se puede utilizar el método $ conjunto con la actualización. (De nuevo, De los documentos ) ... Por lo tanto, si desea establecer ...

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

Enviar como ...

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

Esto ayuda a evitar sobrescribir accidentalmente la totalidad de su documento (s) con { name: 'jason borne' }.

No creo soportes mongodb este tipo de upserting selectiva. Tengo el mismo problema que LeMiz, y con actualización (criterios, newObj, upsert, múltiples) no funciona bien cuando se trata de un tanto 'creada' y 'actualizada' marca de tiempo. Dada la siguiente declaración upsert:

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

Escenario # 1 - documento con el 'nombre' de 'ABC' no existe: Nuevo documento se crea con 'nombre' = 'abc', 'creado' = 2010-07-14 11:11:11 y 'actualizado' = 2010-07-14 11:11:11.

Escenario # 2 - documento con el 'nombre' de 'abc' ya existe con el siguiente: 'Nombre' = 'abc', 'creado' = 2010-07-12 09:09:09, y 'actualizado' = 2010-07-13 10:10:10. Después de la upsert, el documento ahora sería el mismo que el resultado en el escenario # 1. No hay manera de indicar, en una upsert qué campos pueden establecer si la inserción, y que los campos quedarse solo si la actualización.

Mi solución fue crear un índice único en el critera campos, lleve a cabo una inserción, e inmediatamente después realizar una actualización sólo en el campo 'actualizado'.

Resumen

  • Usted tiene una colección existente de registros.
  • Usted tiene un conjunto de registros que contienen cambios a los registros existentes.
  • Algunos de los cambios no se actualizan realmente nada, duplicar lo que ya tiene.
  • Todas las actualizaciones contienen los mismos campos que son ya, solo valores posiblemente diferentes.
  • Usted desea realizar un seguimiento cuando un registro fue modificado ultimamente, en realidad cambia un valor.

Tenga en cuenta, que estoy presumiendo PyMongo, cambiar para adaptarse a su idioma de su elección.

Instrucciones:

  1. Crea la colección con un índice con singular = true para que no se obtiene registros duplicados.

  2. iterar sobre sus registros de entrada, la creación de lotes de ellas de 15.000 registros más o menos. Para cada registro en el lote, crear un diccionario que consiste en los datos que desea insertar, suponiendo que cada uno de ellos va a ser un nuevo récord. Añadir el 'creada' y 'actualizada' marcas de tiempo para estos. Emitir esto como un lote de inserción de comandos con la bandera 'ContinueOnError' = true, por lo que la inserción de todo lo demás que ocurre incluso si hay una clave duplicada en allí (que suena como habrá). Esto sucederá muy rápido. las inserciones roca, he conseguido 15k niveles de rendimiento / segundo. Otras indicaciones relativas a ContinueOnError, consulte http://docs.mongodb.org/manual/core/ cancelaciones de operaciones /

    inserciones

    Record sucede muy rápido, por lo que se hará con las inserciones en ningún momento. Ahora, es el momento de actualizar los registros pertinentes. Hacer esto con una recuperación de lotes, mucho más rápido que una a la vez.

  3. iterar sobre todos los registros de entrada de nuevo, la creación de lotes de 15 K o menos. Extraer las llaves (mejor si hay una clave, pero no se puede evitar si no hay). Recuperar este montón de discos de Mongo con un db.collectionNameBlah.find ({terreno: {$ en: [1, 2,3 ...}) consulta. Para cada uno de estos registros, determinar si hay una actualización, y si es así, emitir la actualización, incluyendo la actualización de la marca de tiempo 'actualizado'.

    Por desgracia, hay que señalar, MongoDB 2.4 y por debajo no incluyen una operación de actualización masiva. Están trabajando en eso.

Puntos de optimización Clave:

  • Los insertos se acelerará enormemente sus operaciones a granel.
  • Discos de Recuperación en masa van a acelerar las cosas, también.
  • actualizaciones individuales son la única ruta posible ahora, pero 10gen está trabajando en él. Presumiblemente, esto será en 2.6, aunque no estoy seguro de si estará terminado para entonces, hay un montón de cosas que hacer (He estado siguiendo su sistema Jira).

En general, se utiliza la actualización es mejor en MongoDB como se acaba de crear el documento si no existe todavía, aunque no estoy seguro de cómo el trabajo que, con su adaptador de pitón.

En segundo lugar, si sólo necesita saber si o no que el documento existe, count () que devuelve sólo un número será una mejor opción que find_one que supuestamente transferir todo el documento de su MongoDB causando el tráfico innecesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top