2012-03-12 10 views
7

tengo una serie de registros como MongoDB:MongoDB: Insertar registro si no existe, si lo hace caso omiso de

{"name":"Bob", "gpa":4} {"name":"Sarah", "gpa":3}

voy a encontrar varios registros adicionales que pueden o no pueda estar relacionada a las mismas personas Quiero aceptarlos si son personas nuevas, y no actualizarlos si son personas que hemos visto antes. Entonces, si obtengo {"name":"Jim", "gpa":2}, quiero aceptarlo tal como está. Si obtengo {"name":"Sarah", "gpa":4} (diferente valor de GPA), quiero simplemente ignorarlo. Esta no parece ser la lógica de update con "upsert" establecido en yes, o de findAndModify con "upsert".

https://stackoverflow.com/a/3260290/514757 sugiere una manera (índice único en el primer campo, inserte el registro, actualice inmediatamente el segundo campo) pero tiene algunos años y me pregunto si ahora hay una mejor manera de hacerlo en un solo paso .

EDIT:

La respuesta aceptada parece muy bien, pero que no funciona para mí! En primer lugar, he creado el índice (esto es con el conductor de Java):

nameIndex.put("name", 1); 
nameIndex.put("unique", true); 
queue.ensureIndex(nameIndex); 

que puedo ver desde la línea de comandos que existe el índice y es único. A continuación, se inserta un artículo:

DBObject person = new BasicDBObject(); 
person.put("name", "Bob"); 
person.put("score", 200000); 
queue.insert(person); 

Más adelante, el artículo con la puntuación más alta tiene su puntuación reduce a cero:

BasicDBObject reset = new BasicDBObject(); 
reset.put("$set", new BasicDBObject("score", 0)); 
DBObject dbObj = queue.findAndModify(null, new BasicDBObject("score", -1), reset); 

Todo esto funciona según lo previsto! Pero, más tarde, se puede encontrar el mismo nombre nuevamente, con una nueva puntuación. Cuando esto último bit de código se ejecuta, un nuevo elemento se crea con una puntuación diferente, que es exactamente lo que no quiero:

BasicDBObject queueable = new BasicDBObject(); 
queueable.put("name", "Could be Bob again, could be someone new"); 
queueable.put("score", 1234); 
queue.insert(queueable); 

Si busco para Bob, me parece:

{ "_id" : ObjectId("4f5e865ad6d09315326ea0f0"), "score" : 0, "name" : "Bob" } 
{ "_id" : ObjectId("4f5e8691d6d09315326ea190"), "name" : "Bob", "score" : 886 } 

Se ha creado un segundo registro, con el puntaje más alto nuevamente. ¿Importa el orden de los campos? No parece que debería, y no sé cómo controlar eso.

+0

el orden de los campos no importa.Si resuelve su llamada de EnsureIndex por la respuesta de @tripvolpe a continuación, debería resolver su problema. por favor acepte la respuesta del viaje si lo hace. – ericsoco

Respuesta

6

Su llamada a ensureIndex() no es del todo correcta. El primer argumento para ensureIndex() contiene las claves que deberían indexarse; las opciones de índice (como la singularidad) se pueden pasar como el segundo argumento. Vea el Java driver docs.

Lo que tienes ahora es intentar crear un índice no único en dos campos: "nombre" y "único".

Prueba esto para crear su índice:

DBObject nameIndex = new BasicDBObject(); 
nameIndex.put("name",1); 

DBObject nameIndexOptions = new BasicDBObject(); 
nameIndexOptions.put("unique", true); 

queue.ensureIndex(nameIndex, nameIndexOptions); 
7

La mejor manera de lograr esto sería la creación de un índice único en el campo de nombre usando:

db.foo.ensureIndex({name:1}, {unique:true}); 

Esto hará que Sarah no se actualiza cuando se realiza una llamada de inserción porque va a encontrar otro récord donde 'Sarah' ya está configurado para el campo de nombre.

+0

Gracias, no me di cuenta de que podría garantizar eso en un solo campo. – umbraphile

+0

Extrañamente, esto no está funcionando. Publiqué un montón de código arriba con la esperanza de que alguien pudiera detectar mi error. – umbraphile

+0

Tengo un problema. Supongo que no lograste resolverlo? – Johan

Cuestiones relacionadas