Java MongoTemplate upsert - 从 pojo(哪个用户编辑过)进行更新的简单方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20001627/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoTemplate upsert - easy way to make Update from pojo (which user has editted)?
提问by vikingsteve
Here is a simple pojo:
这是一个简单的 pojo:
public class Description {
private String code;
private String name;
private String norwegian;
private String english;
}
And please see the following code to apply an upsert
to MongoDb via spring MongoTemplate:
请参阅以下代码以upsert
通过 spring MongoTemplate将 an 应用到 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");
The line to generate the Update
object specifies every field of the Item
class manually.
生成Update
对象的行Item
手动指定类的每个字段。
But if my Item
object changes then my Dao layer breaks.
但是如果我的Item
对象发生变化,那么我的 Dao 层就会中断。
So is there a way to avoid doing this, so that all fields from my Item
class are applied automatically to the update?
那么有没有办法避免这样做,以便我Item
类中的所有字段都自动应用于更新?
E.g.
例如
Update update = new Update().fromObject(item);
Note that my pojo does not extend DBObject
.
请注意,我的 pojo 没有扩展DBObject
。
采纳答案by wvandrunen1982
I ran into the same problem. In het current Spring Data MongoDB version no such thing is available. You have to update the seperate fields by hand.
我遇到了同样的问题。在当前的 Spring Data MongoDB 版本中,没有这样的东西可用。您必须手动更新单独的字段。
However it is possible with another framework: Morphia.
然而,另一个框架是可能的:Morphia。
This framework has a wrapper for DAO functionality: https://github.com/mongodb/morphia/wiki/DAOSupport
这个框架有一个 DAO 功能的包装器:https: //github.com/mongodb/morphia/wiki/DAOSupport
You can use the DAO API to do things like this:
您可以使用 DAO API 执行以下操作:
SomePojo pojo = daoInstance.findOne("some-field", "some-value");
pojo.setAProperty("changing this property");
daoInstance.save(pojo);
回答by stoneHah
I think that: Description add a property
我认为:描述添加属性
@Id
private String id;
then get a document by the query condition,set Description's id by document's id. and save
然后通过查询条件获取一个文档,通过文档的id设置Description的id。并保存
回答by Nimrod007
回答by Vivek Sethi
This is what I am doing for the time being. Not so much elegant way to do it, but it does save a precious DB call:
这就是我目前正在做的事情。没有那么多优雅的方式来做到这一点,但它确实节省了宝贵的数据库调用:
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.fasterxml.Hymanson.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);
}
}
回答by PaniniGelato
I found a pretty good solution for this question
我为这个问题找到了一个很好的解决方案
//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 note that Update.fromDBObject return an update object with all fields in dbDoc. If you just want to update non-null fields, you should code a new method to exclude null fields.
请注意 Update.fromDBObject 返回一个更新对象,其中包含 dbDoc 中的所有字段。如果您只想更新非空字段,您应该编写一个新方法来排除空字段。
For example, the front-end post a doc like below:
例如,前端发布一个文档如下:
//make a new description here
Description d = new Description();
d.setCode("no");
d.setEnglish("norwegian");
We only need to update the field '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);
回答by V. F.
Just use ReflectionDBObject
- if you make Description
extend it, you should just get your object's fields transferred to Update
reflectively, automagically. The note from above about null fields included in the update still holds true.
只需使用ReflectionDBObject
- 如果您Description
扩展它,您应该只Update
反射地、自动地将对象的字段转移到。上面关于更新中包含的空字段的说明仍然适用。
回答by schmichri
If you want to upsert Pojos incl. property String id;
you have to exclude the _id field in the fromDBObject method Update.fromDBObject(dbDoc,"_id"
).
如果你想 upsert Pojos 包括。属性,String id;
您必须在 fromDBObject 方法中排除 _id 字段Update.fromDBObject(dbDoc,"_id"
)。
Otherwise you get the Exception:
否则你会得到异常:
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}
because the _id field of the first is null
因为第一个的 _id 字段为空
{
"_id" : null,
...
}
Fullcode based on @PaniniGelato answer would be
基于@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");
Then the upsert is working in the cases of insert andupdate. Corrections & thoughts are welcome ;)
然后 upsert 在插入和更新的情况下工作。欢迎更正和想法;)
回答by Robert
There are two cases here that need to be distinguished:
这里有两种情况需要区分:
- Update an item that was previously fetched from the DB.
- Update or insert (upsert) an item you created by code.
- 更新先前从数据库中提取的项目。
- 更新或插入(upsert)您通过代码创建的项目。
In Case 1) You can simply use mongoTemplate.save(pojo, "collection"), because your POJO will already have a filled ObjectID in its id field.
在情况 1) 中,您可以简单地使用mongoTemplate.save(pojo, "collection"),因为您的 POJO 在其 id 字段中已经填充了 ObjectID。
In case 2) You have to explain to mongo what "already exists" means in case of your domain model: By default the mongoTemplate.save() method updates an existing item, if there is one with that same ObjectId. But with a newly instantiated POJO you do not have that id. Therefore the mongoTemplate.upsert() method has a query parameter that you can create like this:
在情况 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);
回答by Awanish Kumar
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);
}
}
this is very simple way to save json string into collection using mongodb and spring. This method can be override to use as JSONObject.
这是使用 mongodb 和 spring 将 json 字符串保存到集合中的非常简单的方法。可以覆盖此方法以用作 JSONObject。
回答by Dawid Naczke
The solution for a new spring-data-mongodb version 2.X.X.
spring-data-mongodb 2.XX版新的解决方案
The API has evolved, since 2.X.X version there is:
API 已经发展,从 2.XX 版本开始有:
Update.fromDocument(org.bson.Document object, String... exclude)
instead of (1.X.X):
而不是(1.XX):
Update.fromDBObject(com.mongodb.DBObject object, String... exclude)
The full solution:
完整的解决方案:
//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");
It works!
有用!