Spring Boot Mongo Upsert 数组中的元素

Posted

技术标签:

【中文标题】Spring Boot Mongo Upsert 数组中的元素【英文标题】:Spring Boot Mongo Upsert elements in an array 【发布时间】:2018-06-12 07:32:33 【问题描述】:

想了解如何在 MongoDB 中的给定文档的数组中执行 upsert 操作。

我有以下 json 文档

  
        "firstName": "John",
        "lastName": "Paul",
        "contact": 
            "contactGroup":"Business",
            "myContacts": [
                    "name": "Jeff",
                    "phone": "222 - 572 - 8754"
                ,
                
                    "name": "Joe",
                    "phone": "456 - 875 - 4521"
                
            ]
        
    

我想在以下级别执行 upsert 操作:

    名字 myContacts 数组

下面是我编写的代码 sn-p。目前,我正在为 myContacts 使用 MongoDB 的 addtoSet 运算符,但该行为似乎只向数组添加一个值,除非该值已经存在。

人物类:

@Document
public class Person

    @Id
    private String id;
    private String firstName;
    private String lastName;
    private Contact contact;
    //Setter and Getter methods

联系人类:

public class Contact
    private String contactGroup;
    private List<MyContacts> myContacts;

    //Setter & Getter methods

MyContacts 类:

public class MyContacts

    private String contactName;
    private String contactPhone;

    //Setter and Getter methods

联系人更新:

public class ContacsUpdate 

@Autowired
private MongoOperations mongoOps;


    // This method receives list of person objects
    public void upsertMongoContact(List<Person> persons) 

        for (Person person : persons) 

            Update updateCmd = new Update();
            Query query = new Query();
            query.addCriteria((Criteria.where("firstName").is((person.firstName()))));

            for (MyContacts contact : person.getContact().getmyContacts()) 
                updateCmd.addToSet("contact.myContacts.", contact);
            
            mongoOps.findAndModify(query, updateCmd, FindAndModifyOptions.options().upsert(true), Person.class);
        
    


有什么方法可以根据名称更新 mycontacts 数组。如果不执行插入操作。

【问题讨论】:

您遇到了什么问题? @Remario:如果我更改输入数据中现有联系人的任何电话号码。在数组中添加一个新元素,而不是更新现有的联系人 【参考方案1】:

无法插入数组。

因此,要为快乐路径场景模拟数组的 upsert,您必须在 2 个不同的更新中进行。

下面的代码将寻找具有匹配名称的数组元素,当找到时它将使用更新的电话号码更新匹配的元素;如果没有找到,它将插入一个包含姓名和电话号码的新数组元素。

本质上,我们首先尝试找到名称匹配的数组元素,并在成功时尝试设置电话值,修改后的计数应大于0。 如果它为零,我们必须在数组中插入一个新文档,该文档为此使用推送。这将使用新的数组元素进行更新插入。

类似于 Spring Mongo 2.0.2 版本

 public void upsertMongoContact(List<Person> persons) 

    for (Person person : persons) 
        for (MyContacts contact : person.getContact().getmyContacts()) 
            Query sQuery = new Query();
            Criteria sCriteria = Criteria.where("firstName").is((person.firstName()));
            sCriteria.and("contact.myContacts.name").is(contact.name());
            sQuery.addCriteria(sCriteria);
            Update sUpdate = new Update();
            sUpdate.set("contact.myContacts.$.phone", person.phone());
            UpdateResult sUpdateResult = mongoOps.updateFirst(sQuery, sUpdate, Person.class);
            if (sUpdateResult.getModifiedCount() == 0) 
                Query pQuery = new Query();
                Criteria pCriteria = Criteria.where("firstName").is((person.firstName()));
                pQuery.addCriteria(pCriteria);
                Update pUpdate = new Update();
                pUpdate.push("contact.myContacts", contact);
                mongoOps.updateFirst(pQuery, pUpdate, Person.class);
            
        
    

参考:Updating nested array document in MongoDB

【讨论】:

谢谢你的作品!!在这种情况下可能会出现哪些负面情况? Np。修改后的计数是相当稳定的指标,无论写入是否通过。我们不会进行会导致您插入重复项的原子更新。您可以在第二次更新中使用addToSet 而不是push 来解决重复问题。对于任何其他意外修改的计数,您可以适当地记录它们 是的,我已将代码更新为 addToSet 以避免重复 由于第二个循环遍历 MyContact 列表,如果列表为空,它如何工作? 你能澄清一下update.set()方法中'$'的用法吗?【参考方案2】:

我相信问题出在 addSet 部分。 尝试这个。 删除 addToSet 的 for 循环。 替换为下面

updateCmd.addToSet("myContacts", person)

希望这会有所帮助。

【讨论】:

以上是关于Spring Boot Mongo Upsert 数组中的元素的主要内容,如果未能解决你的问题,请参考以下文章

ThinkPHP Mongo驱动update方法支持upsert参数

Spring Boot + docker +mongo

使用 Spring Boot 在 Mongo 中自动扩展

使用 Mongo 模板在 Spring Boot 中过滤内部 Arraylist 项的 Mongo 查询

Spring Boot + Mongo + JWT

Dockerize Spring Boot mongo