首页 > 解决方案 > How do you remove an element from an array based on element's field value? (Spring-Boot, Reactive MongoDB)

问题描述

I have a Room object. It is essentially a DTO. It has a List or MongoDB an array of User Objects.

For the life of me I can't figure out how to remove a user from the array based on the user's id and couple other things (roomId, roomLeaderId).

public Mono<RoomData> findAndTryKickUser(String roomId, String requestUserId,
        String kickUserId){
    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(roomId).and("roomLeaderId").is(requestUserId)
            .and("userRoomDatas").elemMatch(Criteria.where("userId").is(kickUserId)));

    Update update = new Update();
    update.pull("userRoomDatas.$.userId", kickUserId);
    FindAndModifyOptions options = FindAndModifyOptions.options();
    options.returnNew(true);
    return template.findAndModify(query, update, options, RoomData.class);
}

Now I do have the option to make a User object and place the id in and try to remove the user that way (I haven't tried it yet, but I think that would work), but from my understanding of the placeholder "$" I should be able to remove element.

{"_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"}

EDIT: I made some edits to the code. In part of experimenting with unset but I realized id is actually userId for UserRoomData. Still erroring out in my JUnit tests.

org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 2: 'Cannot apply $pull to a non-array value' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "Cannot apply $pull to a non-array value", "code" : 2, "codeName" : "BadValue" }; nested exception is com.mongodb.MongoCommandException:

标签: javamongodbspring-bootreactive

解决方案


$pull 是数组运算符,它使用查询来匹配和删除嵌入数组中的匹配行。

就像是

 public Mono<RoomData> findAndTryKickUser(String roomId, String requestUserId, String kickUserId){
    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(roomId).and("roomLeaderId").is(requestUserId)
            .and("userRoomDatas").elemMatch(Criteria.where("userId").is(kickUserId)));

    Update update = new Update();
    update.pull("userRoomDatas", new Query().addCriteria(Criteria.where("userId").is(kickUserId)));
    FindAndModifyOptions options = FindAndModifyOptions.options();
    options.returnNew(true);
    return template.findAndModify(query, update, options, RoomData.class);
}

参考

https://docs.mongodb.com/manual/reference/operator/update/pull/#remove-items-from-an-array-of-documents


推荐阅读