query - ¿Cómo actualizo los campos de documentos en mongo db usando el controlador java?
mongodb java example (6)
Referencias:
Todavía es bastante nuevo para mongo db pero estoy intentando actualizar parte de un documento existente dentro de una colección ... desafortunadamente, el enlace de arriba no tiene un ejemplo de actualización.
Esencialmente, solo quiero poder:
- Agregar nuevos campos a un documento
- Actualizar los campos existentes de un documento a un nuevo valor
Aquí está mi código (Grails + Groovy + Java + MongoDB + el controlador java):
def shape = mongo.shapes.findOne(new BasicDBObject("data", "http://www.foo.com")); // get the document
mongo.shapes.update(new BasicDBObject("_id", shape._id), new BasicDBObject("isProcessed", 0)); // add a new "isProcessed" field set to 0
mongo.shapes.update(new BasicDBObject("_id", shape._id), new BasicDBObject("data", "http://www.bar.com"));
Esto prácticamente afecta a todo el objeto ... Podría intentar modificar el objeto de forma original y luego ejecutar la actualización en eso. Pero hasta entonces, ¿alguien tiene experiencia actualizando solo campos individuales (en lugar de todo el documento)?
EDITAR:
Lo probé y pude actualizarlo con éxito enviando todo el objeto con campos nuevos y / o actualizados, y eso funciona. Me pregunto si el controlador es lo suficientemente inteligente como para actualizar solo el subconjunto más pequeño de cambios o si solo se está actualizando a ciegas. (En el caso a continuación, ¿se está actualizando el campo foo a través del cable o el documento completo de la forma?)
Código:
def shape = mongo.shapes.findOne(); // get the first shape to use as a base
shape.removeField("_id"); // remove the id field
shape.put("foo","bar"); // add a new field "foo"
mongo.shapes.insert(shape); // insert the new shape
def shape2 = mongo.shapes.findOne(new BasicDBObject("foo", "bar")); // get the newly inserted shape (and more importantly, it''s id)
shape2.put("foo", "bat"); // update the "foo" field to a new value
mongo.shapes.update(new BasicDBObject("_id", shape2._id), shape2); // update the existing document in mongo
Me pregunto si el controlador es lo suficientemente inteligente como para actualizar solo el subconjunto más pequeño de cambios o si solo se está actualizando a ciegas.
No, si utiliza el método de actualización "normal", todo el objeto se enviará por cable. Sospecho que el servidor de la base de datos será lo suficientemente inteligente como para actualizar solo los índices necesarios (y no los que no cambiaron), si es posible (es decir, el objeto podría actualizarse en el lugar y no fue necesario moverlo porque también creció) mucho)
Lo que puedes hacer es usar las funciones del "modificador de actualización atómica". La documentación de Java es un poco ligera sobre ellos, pero como el controlador simplemente transmite el JSON, las cosas de los tutoriales que no son de Java deberían funcionar, por ejemplo:
shapes.update((DBObject)JSON.parse( "{ ''foo'' : ''bar''}"),
(DBObject) JSON.parse( "{ ''$set'' : { ''foo'': ''bat''}}") );
// actualizar
WriteResult usr = (WriteResult)mongoOperation.upsert(new Query(Criteria.where("name").is("till")),
Update.update("password", "jk45"), "collection");
System.out.println("updatedUser : " + usr );
Encontré un ejemplo aquí , que parece mostrar el uso de la llamada de actualización. Entonces, para tu ejemplo, creo que algo como esto debería funcionar?
// Find an object
def shape2 = mongo.shapes.findOne( new BasicDBObject( ''foo'', ''bar'' ) )
// And update the foo field from ''bar'' to ''bat''
mongo.shapes.update( shape2, new BasicDBObject( ''$set'', new BasicDBObject( ''foo'', ''bat'' ) ) )
Editar
Es posible que puedas usar una categoría para construir tus objetos BasicDBO de una manera más inteligente ...
Algo como esto podría hacerlo:
class BasicDBObjectMapBuilder {
static String toDbObj( String s ) { s }
static BasicDBObject toDbObj( Map m ) {
m.inject( null ) { r, it -> new BasicDBObject( it.key, it.value.toDbObj() ) }
}
}
use( BasicDBObjectMapBuilder ) {
def shape2 = mongo.shapes.findOne( new BasicDBObject( ''foo'', ''bar'' ) )
// And update the foo field from ''bar'' to ''bat''
mongo.shapes.update( shape2, [ ''$set'':[ ''foo'', ''bat'' ] ].toDbObj() )
}
Aunque no he probado esto ...
Editar 2
En realidad, BasicDBObject es un Mapa, por lo que deberías poder hacer:
mongo.shapes.update( shape2, [ ''$set'':[ ''foo'', ''bat'' ] ] as BasicDBObject )
sin necesidad del constructor
Esta respuesta utiliza el shell mongo, pero muestra cómo puede profundizar en la estructura de un objeto JSON para modificar un campo específico sin sobrescribir el resto.
Dado el objeto JSON en una colección llamada ''my_collection'':
{
"_id" : ObjectId("50fdb2a73f7bc7a5acecc4f8"),
"data" : {
"list" : [ 0, 1, 2, 7, 4, 5 ],
"subobj" : {
"var_a":"valuea",
"var_b":"valueb"
}
}
}
Para actualizar ''var_b'', sin sobrescribir nada más:
db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.subobj.var_b":"new_value"}})
Para actualizar el tercer elemento de la matriz ''lista'' con valor ''99'', sin sobrescribir nada más:
db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.list.2":"99"} } )
Muchas de las respuestas en esta publicación están usando versiones anteriores del Mongo Java Driver. Si está utilizando una versión más nueva del controlador Java (v3.0 +), el método preferido parece ser usar el objeto Documento en lugar de la interfaz DBObject.
Aquí hay un ejemplo:
MongoClient client = new MongoClient();
MongoCollection<Document> fooCollection = client.getDatabase("test").getCollection("foo");
Bson filter = Filters.eq("_id", "123d45678c467bb433c99f99");
Bson updates = Updates.set("isFoo", true);
fooCollection.findOneAndUpdate(filter, updates);
DBCollection dbCollection = db.getCollection("mycollection");
BasicDBObject dbObject = new BasicDBObject();
dbObject.put("_id", "3");
// your update condition - or the query
DBObject newObject = dbCollection.find(dbObject).toArray().get(0);
// I just take the first element. Can iterate through as per your requirement if multiple fields exist
newObject.put("key","value");
//add field, either a new field or any existing field
dbCollection.findAndModify(dbObject, newObject);
Sólo tiene que utilizar los pasos anteriores. Puede cambiar los detalles sin afectar otros elementos asociados a la misma clave.