如何在MongoDB中更新嵌套数组元素的字段

时间:2019-06-12 13:10:39

标签: mongodb spring-data-mongodb mongotemplate

我有一个如下文档,我想用给定的MAC和给定的fingerId更新一个AccessPoint的字段,例如RSSI。目前,我正在通过以下方法实现此目的:首先找到accessPoint的索引,然后更新其字段。有什么更好的方法吗?

这是示例文档

"_id" : ObjectId("5d00d45bef388e16b9406b13"), 
    "x" : 7.2, 
    "y" : 4.5, 
    "visitTime" : NumberLong(1560337948058), 
    "gridNumber" : NumberInt(-1), 
    "fingerprints" : [
        {
            "accessPoints" : [
                {
                    "MAC" : "MAC5", 
                    "SSID" : "SSID3", 
                    "RSSI" : NumberInt(20)
                }, 
                {
                    "MAC" : "MAC6", 
                    "RSSI" : NumberInt(20)
                }
            ], 
            "orientation" : NumberInt(0), 
            "fingerId" : NumberInt(0)
        }
    ], 

这就是我目前正在做的事情:

 Query query = new Query(new Criteria().andOperator(
                Criteria.where(Fields._ID).is(new BsonObjectId(new ObjectId(obsId))),
                Criteria.where("fingerprints").elemMatch(Criteria.where("fingerId").is(fingerDoc.getId())),
                Criteria.where("fingerprints.accessPoints").elemMatch(Criteria.where("MAC").is(mac))

        ));

        int index = getIndexOfAP(collection,obsId, mac);

        if(index != -1) {
            Update update = new Update().set("fingerprints.$.accessPoints." + index + ".RSSI", newValue.getRSSI());
            UpdateResult updateResult = mongoTemplate.updateMulti(query, update, collection);
        }

我也尝试使用fingerprints.$.accessPoints.$.RSSI,并且得到too many $ error可以使用除重新设计数据库以外的使用多个$的任何替代解决方案。

  • 请注意,这里只有一个指纹,但是在实际数据中会有很多指纹。

1 个答案:

答案 0 :(得分:0)

这是我考虑到MAC在我的情况下是唯一的事实的解决方案:

  BsonDocument bsonDocument = new BsonDocument();
        bsonDocument.append(Fields._ID,new BsonObjectId(new ObjectId(obsId)));
        bsonDocument.append("fingerprints.fingerId",new BsonInt32(fingerprintDoc.getFingerId()));


        mongoTemplate.getCollection(collection).updateMany(bsonDocument,
                new Document().append("$set", new Document().append("fingerprints.$.accessPoints.$[item].RSSI", newValue.getRSSI())),
                new UpdateOptions()
                        .arrayFilters(
                                Collections.singletonList( Filters.in("item.MAC",
                                        Collections.singletonList(mac)) ))
        );

以这种方式,我首先用给定的ID查找所需的指纹,并更新与mac匹配的accessPoint的RSSI,这就是我要寻找的