Javaドライバーを使用してMongo DBのドキュメントのフィールドを更新するにはどうすればよいですか?
-
01-10-2019 - |
質問
参考文献:
Mongo DBはまだかなり新しいですが、コレクション内の既存のドキュメントの一部を更新しようとしています...残念ながら、上記のリンクには更新の例がありません。
基本的に、私はただできるようにしたいだけです:
- ドキュメントに新しいフィールドを追加します
- ドキュメントの既存のフィールドを新しい値に更新する
これが私のコードです(Grails + Groovy + Java + Mongodb + The Java Driver)は次のとおりです。
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"));
これはオブジェクト全体をほぼ巻き込みます...元のShapeオブジェクトを変更して、それについて更新を実行するだけです。しかしそれまで、 誰もが個々のフィールドだけを(ドキュメント全体ではなく)更新した経験がありますか?
編集:
私はそれを試したばかりで、新しいフィールドおよび/または更新されたフィールドを使用してオブジェクト全体を送信することで正常に更新することができました。ドライバーは、変更の最小のサブセットのみを更新するのに十分賢いのか、それとも全体を盲目的に更新しているのかしら? (以下のケースでは、ワイヤー間の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
解決
ドライバーは、変更の最小のサブセットのみを更新するのに十分賢いのか、それとも全体を盲目的に更新しているのかしら?
いいえ、「通常の」更新方法を使用すると、オブジェクト全体がワイヤー上に送信されます。データベースサーバー自体は、可能であれば、必要なインデックスのみを更新するのに十分なほど賢いと思われます(つまり、オブジェクトを所定の位置に更新することができ、成長したために移動する必要はありませんでした多くの)
できることは、「Atomic Update Modifier」関数を使用することです。 Javaのドキュメントは少し軽いですが、ドライバーはJSONを送信するだけなので、Java以外のチュートリアルからのものは機能するはずです。
shapes.update((DBObject)JSON.parse( "{ 'foo' : 'bar'}"),
(DBObject) JSON.parse( "{ '$set' : { 'foo': 'bat'}}") );
他のヒント
見つかった ここの例, 、更新コールの使用法を示しているようです。あなたの例として、私はこのようなことがうまくいくべきだと思いますか?
// 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' ) ) )
編集
カテゴリを使用して、よりグルーヴィーな方法で基本的なdbobjectsを構築できるかもしれません...
このようなことはそれをするかもしれません:
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 )
ビルダーを必要とせずに
この投稿の多くの答えは、Mongo Javaドライバーの古いバージョンを使用しています。 Javaドライバー(v3.0+)の新しいバージョンを使用している場合、優先された方法は、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);
この答えはMongoシェルを使用しますが、JSONオブジェクト構造に深く入り込んで、残りを上書きせずに特定のフィールドを変更する方法を示しています。
「my_collection」と呼ばれるコレクションのJSONオブジェクトを与えられます:
{
"_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"}})
Array 'list'の3番目の要素をValue '99'で更新し、他のものを上書きせずに更新する。
db.my_collection.update({"_id":"50fdb2a73f7bc7a5acecc4f8"}, { "$set":{"data.list.2":"99"} } )
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);
上記の手順を使用するだけです。同じキーに関連付けられた他のアイテムに影響を与えることなく、詳細を変更できます。
// アップデート
WriteResult usr = (WriteResult)mongoOperation.upsert(new Query(Criteria.where("name").is("till")),
Update.update("password", "jk45"), "collection");
System.out.println("updatedUser : " + usr );