2012-05-20 718 views
18

Considerando una sencilla estructura del documento mongo:mongodb: upserting: valor sólo se establece si el documento está siendo insertado

{_id, firstTime, LastTime}

El cliente tiene que insertar un documento con una identificación conocida, o actualizar un documento existente. El 'último tiempo' siempre debe establecerse en algún momento posterior. Para el 'firstTime', si se está insertando un documento, entonces el 'firstTime' debe establecerse en la hora actual. Sin embargo, si el documento ya está creado, entonces 'firstTime' no se modificará. Me gustaría hacerlo puramente con posturas (para evitar búsquedas).

He rastreado el http://www.mongodb.org/display/DOCS/Updating, pero simplemente no veo cómo se puede hacer esa operación en particular.

No creo que esto sea algo irrazonable, hay operaciones $ push y $ addToSet que efectivamente hacen eso en campos de matriz, simplemente nada que haga lo mismo en campos simples. Es como debería haber algo como $ setSi operación.

+0

* si el documento ya está creado, el campo debe permanecer sin cambios * no se llama upsert (como en su título) –

+0

@ om-nom-nom He esbozado el caso más simple, he actualizado el descripción, por lo que hay un campo que siempre se está actualizando. –

+1

Parece que esta característica está dirigida a 2.4: https://jira.mongodb.org/browse/SERVER-340 – JohnnyHK

Respuesta

27

me encontré con el mismo problema y no había ninguna solución sencilla para obstante < 2.4 desde 2.4 del $ setOnInsert operador vamos a hacer exactamente eso.

db.collection.update(<query>, 
         { $setOnInsert: { "firstTime": <TIMESTAMP> } }, 
         { upsert: true } 
        ) 

Consulte el 2.4 release notes of setOnInsert para obtener más información.

1

No hay forma de hacerlo con solo un inserto. Tendría que hacerlo como 2 operaciones: primero intente insertar el documento; si ya existe, la inserción fallará debido a una violación de clave duplicada en el índice _id. Luego, realiza una operación de actualización para establecer el último tiempo hasta ahora.

+0

En mi humilde opinión, esto frustrará el propósito, el hacer y esperar, la primera operación equivale a una búsqueda sincrónica. No veo una diferencia en "intento de error" y encuentro y actualizo ... –

+1

Hay una condición de carrera con el enfoque de búsqueda y actualización y actualización con varios escritores simultáneos. Si entra otro escritor y crea/cambia el documento entre el primer hilo que hizo la lectura y el momento en que escribe, puede terminar anulando la escritura que hizo el otro hilo. – stbrody

+0

Es por eso que lo quiero en una sola operación de escritura(), por lo que pedirle a Mongo que lo ejecute atómicamente. –

1

me encontré con un problema muy similar al intentar upsert documentos basados ​​en el contenido existente - tal vez esta solución funcionará para usted también:

intente eliminar el atributo _id de su registro y sólo lo utilizan en la consulta parte de su actualización (que tendrá que traducir del pymongo hablan ...)

myid = doc.get('_id') 
del doc['_id'] 
mycollection.update({'_id':myid}, {'$set':doc}, upsert=True) 
Cuestiones relacionadas