Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java MongoTemplateUpsert-从pojo(哪个用户编辑过)进行更新的简单方法?_Java_Mongodb_Upsert_Mongotemplate - Fatal编程技术网

Java MongoTemplateUpsert-从pojo(哪个用户编辑过)进行更新的简单方法?

Java MongoTemplateUpsert-从pojo(哪个用户编辑过)进行更新的简单方法?,java,mongodb,upsert,mongotemplate,Java,Mongodb,Upsert,Mongotemplate,以下是一个简单的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

以下是一个简单的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");
生成
更新
对象的行手动指定
类的每个字段

但是,如果我的
对象发生更改,那么我的Dao层就会中断

那么有没有一种方法可以避免这样做,这样我的
Item
类中的所有字段都会自动应用于更新

例如


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

,我遇到了相同的问题。在当前的SpringDataMongoDB版本中,没有这样的东西可用。您必须手动更新单独的字段

然而,有了另一个框架:Morphia,这是可能的

此框架具有DAO功能的包装器:

您可以使用DAO API执行以下操作:

SomePojo pojo = daoInstance.findOne("some-field", "some-value");
pojo.setAProperty("changing this property");
daoInstance.save(pojo);
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);
我认为: 说明添加属性

@Id
private String id;
然后根据查询条件获取文档,根据文档id设置描述id。 和save

您可以使用save:(如果不存在=insert else=upsert)

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


阅读:

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

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

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

//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中的所有字段。如果您只想更新非空字段,那么应该编写一个新方法来排除空字段

例如,前端post文档如下所示:

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

只需使用
ReflectionDBObject
-如果您对其进行
Description
扩展,您只需将对象的字段以反射方式自动传输到
Update
。上面关于更新中包含的空字段的注释仍然有效。

如果您想向上插入包含属性的POJO
字符串id
必须排除fromDBObject方法
Update.fromDBObject(dbDoc,“\u id”
)中的_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在insert更新的情况下工作。欢迎更正和思考;)

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

  • 更新以前从数据库中获取的项
  • 更新或插入(向上插入)由代码创建的项
  • 在案例1)中,您可以简单地使用,因为POJO的id字段中已经有一个填充的ObjectID

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

    SomePojo pojo = daoInstance.findOne("some-field", "some-value");
    pojo.setAProperty("changing this property");
    daoInstance.save(pojo);
    
    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);
    
    这是使用mongodb将json字符串保存到集合中的非常简单的方法 还有春天。
    可以重写此方法以用作JSONObject。

    新spring data mongodb 2.X.X版的解决方案

    自2.X.X版本以来,API不断发展,有:

    Update.fromDocument(org.bson.Document object, String... exclude)
    
    而不是(1.X.X):

    完整解决方案:

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

    它起作用了

    正如前面的答案所说,使用mongoTemplate.getConverter().write()和Update.fromDocument()函数。但是我发现Update.fromDocument()不会添加“$set”键,也不会直接工作,解决方案是自己添加“$set”,如下所示(注意:我使用的是2.2.1.RELEASE版本):

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

    @starkk92 plz注意Update.fromDBObject将替换dbDoc中的所有字段。如果你只想用非空字段创建更新,你必须自己编写代码。答案是OK,但这也会设置空对象。如果不希望更新空对象,则必须包含一个ObjectMapper,并带有忽略inlcudes的选项。这是@gogstad对Vivek Sethi答案的评论。顺便说一句,谢谢。您需要确保
    ObjectMapper
    没有序列化空值:
    String jsonStr=ObjectMapper.copy().setSerializationInclusion(JsonInclude.Include.NON_NULL)。writeValueAsString(object)警告:如果您在实体中使用带有
    @Version
    -标记的字段,此方法将干扰spring的版本增量,产生异常“无效BSON字段名$inc”。在这种情况下,必须迭代dbDoc并使用@PaniniGelatos answer中的
    update.set
    。真正不鼓励只使用代码的答案。为了帮助未来的读者,请解释一下你正在做什么!为什么这对批量操作不起作用?这里有一段代码java.lang.IllegalArgumentException:无效的BSON字段名code@madcolonel10你找到解决办法了吗?我也有同样的问题。@chris115379检查这是否有帮助
    @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);
    }
    
    public static Update updateFromObject(Object object, MongoTemplate mongoTemplate) {
        Document doc = new Document();
        mongoTemplate.getConverter().write(object, doc);
        return Update.fromDocument(new Document("$set", doc));
    }