【问题标题】:How to update part of a document inside an array? (MongoDB SpringBoot Reactive)如何更新数组内的部分文档? (MongoDB Spring Boot 反应式)
【发布时间】:2018-07-11 22:53:29
【问题描述】:

我知道这个问题已经得到了很多人的回答。但是,我无法找到“正确”执行此操作的 Spring Boot 方式。我找到了一些例子,但我无法让它适用于我的项目。

{"_id":"5b45572047f84e3d10c59b8a"
,"userRoomDatas":[{"isInGame":false,"isReady":true,"isSpectator":false,"userId":"5b45572047f84e3d10c59b84"}]
,"selectedScreen":"MATCHMAKING"
,"privacySetting":"PUBLIC"
,"roomLeaderId":"5b45572047f84e3d10c59b84"
,"botHostId":"5b45572047f84e3d10c59b84"
,"matchmakingData":   {"selectedQueId":"5b45572047f84e3d10c59b85","matchmakingRating":"M3"}
,"currentRoomStatus":"IN_ROOM"
,"canStartSearch":false
,"password":"AA=="
,"quickJoinEnabled":true
,"roomRating":"MEMERS_ONLY"
,"_class":"room"}

这是我的文件。我希望能够更改 userRoomDatas 中的一个对象的值。例如 "isSpectator":false 到 "isSpectator":true

public Mono<RoomData> findAndModifyUserSpectate(String roomId, String requestUserId,
        boolean isSpecator){
    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(roomId).and("userRoomDatas")
            .elemMatch(Criteria.where("userId").is(requestUserId)));
    Update update = new Update();
    update.set("userRoomDatas.$.isSpectator : " + isSpecator, new Query(Criteria
            .where("userRoomDatas").elemMatch(Criteria.where("userId").is(requestUserId))));
    FindAndModifyOptions options = FindAndModifyOptions.options();
    options.returnNew(true);
    return template.findAndModify(query, update, options, RoomData.class);
}

这是我得到的最好的。我尝试了不同的方法,但我知道它们都错了。

根据我的理解,第一个查询过滤掉了我的 RoomData 对象。但是更新部分我不知道如何引用数组中的文档并告诉它用新值更新其中一个变量。我知道关键部分没有多大意义。我尝试了不同的方法,但我不知道将查询与值放在哪里。

【问题讨论】:

    标签: java spring-boot mongodb-query reactive-programming


    【解决方案1】:

    这是一个旧帖子,但我希望这可以帮助其他人。 更新数组内文档的最通用方法是使用 MongoDB arrayFilters。使用 springboot 没有使用 MongoTemplate 的直接连接,但可以使用 MongoDatabase 对象。

    一个实际的例子很简单。假设有一个类似

    的文档
    { _id: "132456",
      statistics:
        2018: [
          {
             offset: 5,
             results: {
                a: 1,
                b: 2
             }
          },
          {
             offset: 4,
             results: {
                a: 13,
                b: 24
             }
          }
        ]
    }
    

    更新的 Java 代码如下所示

    // Defines the query which selects the document
    Bson filter = Filters.and(Filters.eq("_id", "132456"), Filters.exists("statistics"));
    
    // Defines the udpate command. Notice the filtered positional operator $[element]
    Bson update = Updates.set("statistics.$[element].results.b", result);
    
    // IMPORTANT! This select the document into the array. 
    // Notice that the document does not really contain a key called "element": 
    // it is only a parametric variable later referenced in the arrayFilters
    UpdateOptions updateOptions = new UpdateOptions();
    List<Bson> arrayFilters = new ArrayList();
    Bson arrayElement = Filters.eq("element.daysOffset", -4);
    arrayFilters.add(arrayElement);
    updateOptions.arrayFilters(arrayFilters);
    
    // Finally update the element matching both the document in the collection 
    // and the document in the inner array
    mongoTemplate.getDb().getCollection("MyCollection").updateOne(filter, update, updateOptions);
    

    【讨论】:

      【解决方案2】:

      我是个白痴。在创建我的文档时,我没有发送正确的 UserRoomData 对象,因此用户从未添加到 Room,这就是我取消的原因。我正确地将正确的用户添加到了房间(正确地传递了正确的 userId),并且在我做出绝望的改变之前也改变了我拥有它的方式。

      public Mono<RoomData> findAndModifyUserSpectate(String roomId, String requestUserId,
              boolean isSpecator){
          Query query = new Query();
          query.addCriteria(Criteria.where("id").is(roomId).and("userRoomDatas")
                  .elemMatch(Criteria.where("userId").is(requestUserId)));
          Update update = new Update();
          update.set("userRoomDatas.$.isSpectator", isSpecator);
          FindAndModifyOptions options = FindAndModifyOptions.options();
          options.returnNew(true);
          return template.findAndModify(query, update, options, RoomData.class);
      }
      

      我仍然不明白占位符如何知道要替换的正确 UserRoomData。我知道在查询中我有一个 eleMatch,但我不明白在查询后它如何知道要替换是否有意义。我一直认为查询是为了获取正确的 Room 对象,而不是能够获取 UserRoomData 对象。

      编辑:以为我错了。问题归结为我将同一个用户两次添加到列表中。其中一位用户正在正确更改,另一位则没有。因此,当我进行我的asssertEquals 测试时,它返回的是没有改变的那个,因此测试失败了。这虽然有效。我只需要删除添加相同的用户。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-19
        • 1970-01-01
        • 1970-01-01
        • 2016-12-18
        • 2021-04-17
        相关资源
        最近更新 更多