Как обновить поля документов в mongo db с помощью java-драйвера?

Использованная литература:

Все еще новичок в mongo db, но я пытаюсь обновить часть существующего документа внутри коллекции... к сожалению, в приведенной выше ссылке нет примера обновления.

По сути, я просто хочу иметь возможность:

  1. Добавление новых полей в документ
  2. Обновить существующие поля документа до нового значения

Вот мой код (Grails + Groovy + Java + MongoDB + драйвер 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"));

Это в значительной степени стирает весь объект... Я мог бы попробовать просто изменить исходный объект формы, а затем запустить обновление для него. Но до тех пор у кого-нибудь есть опыт обновления отдельных полей (а не всего документа)?

РЕДАКТИРОВАТЬ:

Я только что попробовал и смог успешно обновить, отправив весь объект с новыми и/или обновленными полями, и это работает. Интересно, достаточно ли умен драйвер, чтобы обновлять только наименьшее подмножество изменений или он просто вслепую обновляет все? (В приведенном ниже случае это просто обновление поля foo по проводу или всего документа формы?)

Код:

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

person longda    schedule 27.08.2010    source источник


Ответы (6)


Интересно, достаточно ли умен драйвер, чтобы обновлять только наименьшее подмножество изменений или он просто вслепую обновляет все?

Нет, если вы используете «обычный» метод обновления, весь объект будет отправлен по сети. Подозреваю, что сам сервер базы данных будет достаточно умен, чтобы обновлять только нужные индексы (а не те, которые не изменились), если это возможно (т.е. объект можно было обновить на месте и его не нужно было перемещать, потому что он слишком вырос много)

Что вы можете сделать, так это использовать функции «атомарного модификатора обновления». В документации по Java их немного мало, но, поскольку драйвер просто передает JSON, материал из руководств, не относящихся к Java, должен работать, например:

shapes.update((DBObject)JSON.parse(    "{ 'foo' : 'bar'}"),  
    (DBObject) JSON.parse(          "{ '$set' : { 'foo': 'bat'}}")   );
person Thilo    schedule 27.08.2010
comment
Спасибо! Я думаю, что этот код мне нравится немного больше, так как он немного понятнее стандартного синтаксиса... Я попробую. - person longda; 27.08.2010
comment
Я пробовал это и не мог заставить его проанализировать. Ему не понравились одинарные кавычки, и тогда второй JSON.parse нельзя привести к DBObject (это HashMap). - person Gandalf; 19.10.2010
comment
@Gandalf: Извините, непроверенный код. Но он должен быть очень похож на предыдущий. - person Thilo; 20.10.2010

Нашел здесь пример, который, похоже, показывает использование звонок обновления. Итак, для вашего примера, я считаю, что что-то вроде этого должно работать?

// 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' ) ) )

Редактировать

Возможно, вы сможете использовать категорию для более удобного построения ваших объектов BasicDBObject...

Что-то вроде этого может сделать это:

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

Я не проверял это, хотя...

Редактировать 2

На самом деле BasicDBObject — это карта, поэтому вы должны уметь:

  mongo.shapes.update( shape2, [ '$set':[ 'foo', 'bat' ] ] as BasicDBObject )

не нуждаясь в застройщике

person tim_yates    schedule 27.08.2010
comment
МОИ ГЛАЗА! ОНИ ГОРЯТ! Большое вам спасибо за это, теперь это имеет смысл... код, который они заставляют нас писать для этого, НАСТОЛЬКО уродлив! :) - person longda; 27.08.2010
comment
хахаха ... да ... Я сделал грубую попытку создать категорию DBObjects из карты в качестве редактирования ... но не проверял это ... - person tim_yates; 28.08.2010
comment
Да, Java делает работу с JSON уродливой. Драйвер Java должен предоставлять способы передачи строк JSON (но этому также мешает отсутствие многострочных строк и альтернативных символов кавычек в Java), а также некоторые методы построения со значимыми именами (поэтому вам не нужно набирать $set ). - person Thilo; 28.08.2010

Многие ответы на этот пост используют более старые версии драйвера Mongo Java. Если вы используете более новую версию драйвера Java (v3.0+), то предпочтительным методом является использование объекта Document вместо интерфейса DBObject.

Вот пример:

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);
person robjwilkins    schedule 18.01.2016
comment
Я попробовал ваш подход, но он не работает для Java-драйвера MongoDB 3.2. - person Mike B.; 28.02.2016

В этом ответе используется оболочка mongo, но показано, как вы можете углубиться в структуру объекта JSON, чтобы изменить определенное поле, не перезаписывая остальные.

Учитывая объект JSON в коллекции под названием «my_collection»:

{ 
  "_id" : ObjectId("50fdb2a73f7bc7a5acecc4f8"), 
  "data" : { 
    "list" : [ 0, 1, 2, 7, 4, 5 ], 
    "subobj" : { 
       "var_a":"valuea",
       "var_b":"valueb" 
     }
  }
}

Чтобы обновить 'var_b', ничего не перезаписывая:

db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.subobj.var_b":"new_value"}})

Чтобы обновить 3-й элемент в массиве «список» со значением «99», ничего не перезаписывая:

db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.list.2":"99"} } )
person ElStepherino    schedule 21.01.2013

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);

Просто используйте описанные выше шаги. Вы можете изменить детали, не затрагивая другие элементы, связанные с тем же ключом.

person Arun A K    schedule 24.08.2012

// Обновить

WriteResult usr = (WriteResult)mongoOperation.upsert(new  Query(Criteria.where("name").is("till")),  

Update.update("password", "jk45"), "collection");

System.out.println("updatedUser : " + usr );
person user2164052    schedule 25.03.2013