【问题标题】:Remove an array entry in an object using spring data mongodb使用spring data mongodb删除对象中的数组条目
【发布时间】:2012-08-21 11:46:08
【问题描述】:

我最近花了一些时间尝试通过 Spring 的 Data MongoOperations 接口使用 $pull 运算符,所以我认为如果有人遇到类似问题,分享我的发现会很好。

就这样吧……

我有 2 个类似的 java POJO:

@Document
public class OutterObject{

    private String id;
    private String name;
    private List<InnerDocument> innerDocs;


    //SETTERS - GETTERS Ommited


public class InnerDocument{


    private String id;
    private String name;

         //SETTERS - GETTERS Ommited

这像这样存储在 Mongo 集合中:

 "_id" : "doc2",
 "_class" : "OutterObject",
 "name" : "doc2",
 "innerDocs" : [{
      "_id" : "innerDoc21",
      "name" : "innerDoc21"
  }, {
      "_id" : "innerDoc22",
      "name" : "innerDoc22"
  }]

我正在尝试使用 $pull 运算符来删除 innerDoc 集合中名称值为“innerDoc22”的所有对象。

我知道如何使用 mongo 驱动程序来完成此任务:

 List<String> ids = 
         Arrays.asList("innerDoc22");

 BasicDBObject find = new BasicDBObject();

 match.put("innerDocs.name", 
           BasicDBObjectBuilder.start("$in", ids).get());

    BasicDBObject update = new BasicDBObject();
        update.put(
                "$pull",
                BasicDBObjectBuilder.start("innerDocs",
                        BasicDBObjectBuilder.start("name", "innerDoc22").get()).get());

  DBCollection col= mongoOperations.getDb().getCollection("outterObject");

  col.update(find , update);

我正在尝试使用 Spring 的 MongoOperations 接口来完成同样的事情。 这是我使用 MongoOperations 接口的代码:

List<String> ids = Arrays.asList("innerDoc22");

Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));

WriteResult wc = mongoOperations.upsert(
                    removeQuery, 
                    new Update().pull("innerDocs.name", "innerDoc22"), 
                    OutterObject.class);
System.out.println(wc.getLastError());

我在调用getLastError() 时没有收到任何错误,数据库中根本没有完成更新。

我知道here 已经有人问过类似的问题,但给出的答案没有使用 MongoOperations 界面。

【问题讨论】:

    标签: mongodb spring-data


    【解决方案1】:

    经过一番搜索并查看源代码后,我意识到我需要将 InnerDocument 对象作为第二个参数传递给 pull 方法,以便 spring 类能够正确地进行映射。

    事实证明,我可以在选择对象时导航对象(我在 removeQuery 中使用“innerDocs.name”),但在更新文档时我不能(或没有找到方法)这样做。

    以下是我如何使用 MongoOperations 实现查询:

    List<String> ids = Arrays.asList("innerDoc22", "innerDoc21");
    
    Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));
    
    WriteResult wc = 
           mongoOperations.upsert(removeQuery, 
               new Update().pull("innerDocs", 
               new InnerDocument("innerDoc22", null)), 
               OutterObject.class);
    
    System.out.println(wc.getLastError());
    

    【讨论】:

    【解决方案2】:

    您也可以使用 BasicDBObject 代替 InnerDocument,我是偶然发现的。通过打印更新对象,可以看到实际的mongo shell查询json,对调试非常有帮助。 :

    Update updateObj = new Update()
             .pull("innerDocs", new BasicDBObject("innerDocs.name","innerDoc22"));
    
    System.out.println("UPDATE OBJ: " + updateObj.toString());
    

    结果:

    UPDATE OBJ: { "$pull" : { "innerDocs" : { "innerDocs.name" : "innerDoc22"}}}

    【讨论】:

      【解决方案3】:

      我尝试了 med116 给出的解决方案,我不得不修改它才能工作:

      Update updateObj = new Update().pull("innerDocs", new BasicDBObject("name","innerDoc22"));
      

      因为否则我的数组中没有匹配的对象。

      【讨论】:

      • 是的,将“innerDocs.name”更改为“name”就像一个魅力!
      【解决方案4】:

      在spring data mongo中,就像这样:

      
      //remove array's one elem
      UpdateResult wc = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").is("java"))),TestPull.class);
      //remove array's multi-elem
      UpdateResult wc1 = mongoTemplate.upsert(removeQuery,new Update().pull("tags",Query.query(Criteria.where("tag").in(Arrays.asList("mongo", "netty")))),TestPull.class);
      

      【讨论】:

        【解决方案5】:

        如果您只是想从数组中删除一个没有任何其他属性(如名称)的元素,请编写您希望的查询并

        Update update = new Update();
        update.pull("Yourarrayname","valueyouwishtodelete");  
        mongoTemplate.upsert(query,update,"collectionname");
        

        【讨论】:

          【解决方案6】:

          这是我的解决方案 - 感谢@ufasoli:

            public Mono<ProjectChild> DeleteCritTemplChild(String id, String idch) {
              Query query = new Query();
              query.addCriteria(Criteria
                                     .where("_id")
                                     .is(id)
                                     .and("tasks._id")
                                     .is(idch)
                               );
          
              Update update = new Update();
              update.set("tasks.$", null);
          
              return template
                   // findAndModify:
                   // Find/modify/get the "new object" from a single operation.
                   .findAndModify(
                        query, update,
                        new FindAndModifyOptions().returnNew(true), ProjectChild.class
                                 );
            }
          

          【讨论】:

            【解决方案7】:

            这对我有用!

            UpdateResult updateResult = mongoTemplate.updateMulti(new Query(where("id").is(activity.getId())), new Update().pull("comments", new Query(where("id").is(commentId))), Activity.class);
            

            它将生成:

            Calling update using query: { "_id" : { "$oid" : "61f900e7c7b79442eb3855ea"}} and update: { "$pull" : { "comments" : { "_id" : "61fac32e3f9ab5646e016bc8"}}} in collection: activity
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-06-08
              • 1970-01-01
              • 2021-11-09
              • 1970-01-01
              • 2013-03-16
              相关资源
              最近更新 更多