web-dev-qa-db-ja.com

MongoTemplate upsert-pojo(どのユーザーが編集した)から更新を行う簡単な方法?

ここに単純なpojoがあります:

public class Description {
    private String code;
    private String name;
    private String norwegian;
    private String english;
}

また、次のコードを参照して、Spring MongoTemplateを介してupsertをMongoDbに適用してください。

Query query = new Query(Criteria.where("code").is(description.getCode()));
Update update = new Update().set("name", description.getName()).set("norwegian", description.getNorwegian()).set("english", description.getEnglish());
mongoTemplate.upsert(query, update, "descriptions");

Updateオブジェクトを生成する行は、Itemクラスのすべてのフィールドを手動で指定します。

ただし、Itemオブジェクトが変更されると、Daoレイヤーが壊れます。

これを回避して、Itemクラスのすべてのフィールドが更新に自動的に適用されるようにする方法はありますか?

例えば。

Update update = new Update().fromObject(item);

私のpojoはDBObjectを拡張しないことに注意してください。

17
vikingsteve

私も同じ問題に遭遇しました。現在のSpring Data MongoDBバージョンでは、そのようなものはありません。個別のフィールドを手動で更新する必要があります。

しかし、それは別のフレームワークで可能です:Morphia。

このフレームワークには、DAO機能のラッパーがあります。 https://github.com/mongodb/morphia/wiki/DAOSupport

DAO APIを使用して、次のようなことを行うことができます。

SomePojo pojo = daoInstance.findOne("some-field", "some-value");
pojo.setAProperty("changing this property");
daoInstance.save(pojo);
0
wvandrunen1982

この質問にはかなり良い解決策を見つけました

//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");

//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));

//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc);

//run it!
mongoTemplate.upsert(query, update, "descriptions");

Plzは、Update.fromDBObjectがdbDocのすべてのフィールドを持つ更新オブジェクトを返すことに注意してください。 null以外のフィールドを更新するだけの場合は、新しいメソッドをコーディングしてnullフィールドを除外する必要があります。

たとえば、フロントエンドは以下のようなドキュメントを投稿します。

//make a new description here
Description d = new Description();
d.setCode("no");
d.setEnglish("norwegian");

「language」フィールドを更新するだけです。

//return Update object
public static Update fromDBObjectExcludeNullFields(DBObject object) {
    Update update = new Update();       
    for (String key : object.keySet()) {
        Object value = object.get(key);
        if(value!=null){
            update.set(key, value);
        }
    }
    return update;
}

//build udpate
Update update = fromDBObjectExcludeNullFields(dbDoc);
19
PaniniGelato

新しいspring-data-mongodbバージョン2.X.Xのソリューション。

2.X.Xバージョン以降、APIは進化しました。

Update.fromDocument(org.bson.Document object, String... exclude)

(1.X.X)の代わりに:

Update.fromDBObject(com.mongodb.DBObject object, String... exclude)

完全なソリューション:

//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
Query query = new Query(Criteria.where("code").is(description.getCode()));

Document doc = new Document(); // org.bson.Document
mongoTemplate.getConverter().write(item, doc);
Update update = Update.fromDocument(doc);

mongoTemplate.upsert(query, update, "descriptions");

できます!

9
Dawid Naczke

保存を使用できます:(存在しない場合=挿入する場合=アップサート)

save(Object objectToSave、String collectionName)

読み取り: javadoc

6
Nimrod007

とりあえずこれをやっています。エレガントな方法ではありませんが、貴重なDB呼び出しを節約できます。

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;

/**
 * Perform an upsert operation to update ALL FIELDS in an object using native mongo driver's methods
 * since mongoTemplate's upsert method doesn't allow it
 * @param upsertQuery
 * @param object
 * @param collectionName
 */
private void performUpsert(Query upsertQuery, Object object, String collectionName){

    ObjectMapper mapper = new ObjectMapper();

    try {
        String jsonStr = mapper.writeValueAsString(object);
        DB db = mongoTemplate.getDb();
        DBCollection collection = db.getCollection(collectionName);
        DBObject query = upsertQuery.getQueryObject();
        DBObject update = new BasicDBObject("$set", JSON.parse(jsonStr));
        collection.update(query, update, true, false);
    } catch (IOException e) {
        LOGGER.error("Unable to persist the metrics in DB. Error while parsing object: {}", e);
    }
}
2
Vivek Sethi

あなたが含むPojosをupsertしたい場合。プロパティString id; fromDBObjectメソッドの_idフィールドを除外する必要がありますUpdate.fromDBObject(dbDoc,"_id")。

それ以外の場合は、例外が発生します。

org.springframework.dao.DuplicateKeyException: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}; nested exception is com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}

最初の_idフィールドがnullであるため

{
    "_id" : null,
...

}

@PaniniGelatoの回答に基づくフルコードは

public class Description(){
    public String id;
...
}

Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");

//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));

//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc, "_id");

//run it!
mongoTemplate.upsert(query, update, "descriptions");

その後、挿入and updateの場合にアップサートが機能します。修正と考えは大歓迎です;)

2
Chris

ここで区別する必要がある2つのケースがあります。

  1. 以前にDBからフェッチされたアイテムを更新します。
  2. コードで作成したアイテムを更新または挿入(アップサート)します。

ケース1)では、POJOのidフィールドにObjectIDが既に入力されているため、単純に mongoTemplate.save(pojo、 "collection") を使用できます。

ケース2)ドメインモデルの場合、「すでに存在する」の意味をmongoに説明する必要があります。デフォルトで、mongoTemplate.save()メソッドは、同じObjectIdを持つアイテムがある場合、既存のアイテムを更新します。しかし、新しくインスタンス化されたPOJOでは、そのIDはありません。したがって、mongoTemplate.upsert()メソッドには、次のように作成できるクエリパラメータがあります。

MyDomainClass pojo = new MyDomainClass(...);

Query query = Query.query(Criteria.where("email").is("[email protected]"));

DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(pojo, dbDoc);   //it is the one spring use for convertions.
dbDoc.removeField("_id");    // just to be sure to not create any duplicates
Update update = Update.fromDBObject(dbDoc);

WriteResult writeResult = mongoTemplate.upsert(query, update, UserModel.class);
1
Robert

以前の回答で述べたように、mongoTemplate.getConverter()。write()およびUpdate.fromDocument()関数を使用します。しかし、Update.fromDocument()が「$ set」キーを追加せず、直接機能しないことがわかりました。解決策は、以下のように「$ set」を自分で追加することです(PS:2.2.1.RELEASEバージョンを使用しています) ):

public static Update updateFromObject(Object object, MongoTemplate mongoTemplate) {
    Document doc = new Document();
    mongoTemplate.getConverter().write(object, doc);
    return Update.fromDocument(new Document("$set", doc));
}
1
arthurdai

ReflectionDBObjectを使用するだけです。Descriptionを拡張すると、オブジェクトのフィールドが自動的にUpdateに反射的に転送されます。更新に含まれるnullフィールドに関する上記の注意事項は引き続き当てはまります。

0
V. F.
@Override
public void updateInfo(UpdateObject algorithm) {
    Document document = new Document();
    mongoTemplate.getConverter().write(algorithm, document);
    Update update = Update.fromDocument(document);
    mongoTemplate.updateFirst(query(where("_id").is(algorithm.get_id())), update, UpdateObject.class);
}
0
字云龙
public void saveOrUpdate(String json) {
    try {
        JSONObject jsonObject = new JSONObject(json);
        DBObject update1 = new BasicDBObject("$set", JSON.parse(json));
        mongoTemplate.getCollection("collectionName").update(new Query(Criteria.where("name").is(jsonObject.getString("name"))).getQueryObject(), update1, true, false);
    } catch (Exception e) {
        throw new GenericServiceException("Error while save/udpate. Error msg: " + e.getMessage(), e);
    }

}

これは、mongodbとspringを使用してjson文字列をコレクションに保存する非常に簡単な方法です。このメソッドをオーバーライドして、JSONObjectとして使用できます。

0
Awanish Kumar

私はそう思います:説明はプロパティを追加します

@Id
private String id;

次に、クエリ条件でドキュメントを取得し、説明のIDをドキュメントのIDで設定します。と保存

0
stoneHah