21

这是一个简单的pojo:

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

请参阅以下代码以upsert通过 spring MongoTemplate 应用到 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对象发生了变化,那么我的道层就会中断。

那么有没有办法避免这样做,以便我Item班级的所有字段都自动应用于更新?

例如

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

请注意,我的 pojo 没有扩展DBObject.

4

12 回答 12

21

我为这个问题找到了一个很好的解决方案

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

请注意,Update.fromDBObject 返回一个包含 dbDoc 中所有字段的更新对象。如果您只想更新非空字段,您应该编写一个新方法来排除空字段。

例如,前端发布如下文档:

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

我们只需要更新“语言”字段:

//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);
于 2016-01-22T09:27:18.600 回答
12

spring-data-mongodb 2.XX 新版本的解决方案

API 已经进化,从 2.XX 版本开始有:

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

而不是(1.XX):

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

有用!

于 2018-07-09T08:31:49.527 回答
6

您可以使用保存:(如果不存在 = 插入 else = upsert)

保存(对象 objectToSave,字符串集合名称)

阅读:javadoc

于 2014-10-07T08:34:01.747 回答
5

就像之前的答案所说,使用 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));
}
于 2019-11-27T09:27:23.737 回答
2

如果你想更新 Pojos,包括。属性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 字段为空

{
    "_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");

然后 upsert 在插入更新的情况下工作。欢迎更正和想法;)

于 2016-09-02T10:41:02.353 回答
1

这就是我目前正在做的事情。不是那么优雅的方式,但它确实节省了宝贵的数据库调用:

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);
    }
}
于 2015-08-06T16:23:04.650 回答
1

这里有两种情况需要区分:

  1. 更新之前从数据库中获取的项目。
  2. 更新或插入(更新插入)您通过代码创建的项目。

在案例 1) 中,您可以简单地使用mongoTemplate.save(pojo, "collection"),因为您的 POJO 的 id 字段中已经有一个填充的 ObjectID。

在案例 2) 中,您必须向 mongo 解释在您的域模型中“已经存在”的含义:默认情况下,mongoTemplate.save() 方法会更新现有项目,如果有一个具有相同 ObjectId 的项目。但是对于新实例化的 POJO,您没有该 ID。因此 mongoTemplate.upsert() 方法有一个查询参数,您可以像这样创建:

MyDomainClass pojo = new MyDomainClass(...);

Query query = Query.query(Criteria.where("email").is("user1@domain.com"));

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);
于 2016-12-26T20:42:55.337 回答
0

我遇到了同样的问题。在当前的 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);
于 2014-03-05T23:51:09.033 回答
0

我认为:描述添加一个属性

@Id
private String id;

然后通过查询条件得到一个文档,通过文档的id设置Description的id。并保存

于 2014-05-14T09:44:04.393 回答
0

只需使用ReflectionDBObject- 如果你Description扩展它,你应该让你的对象的字段Update反射性地自动传输。上面关于更新中包含的空字段的注释仍然适用。

于 2016-06-07T01:10:18.213 回答
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。

于 2018-03-22T17:50:07.180 回答
-1
@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);
}
于 2018-10-30T12:00:05.573 回答