在mongodb键值子文档上设置$时出现打字错误

m1m5dgzv  于 2023-02-11  发布在  Go
关注(0)|答案(1)|浏览(102)

这是示例记录。

{
    _id: ObjectId('63e501cc2054071132171098'),
    name: 'Ricky',
    discriminator: 7706,
    registerTime: ISODate('2023-02-09T14:23:08.159Z'),
    friends: {
        '63e502f4e196ec7c04c4351e': {
            friendId: ObjectId('63e502f4e196ec7c04c4351e'),
            friendshipStatus: null,
            privateChannelId: ObjectId('63e66dd85eb6c3cc248ecc95'),
            active: true
        }
    }
}

我想将属性“friends.63e502f4e196ec7c04c4351e.friendshipStatus”从null更新为1,但不替换整个子文档(我想保留“friendId”、“privateChannelId”和“active”属性
目前我已经尝试

const friendUpdateResult = await collections.users!.updateOne(
  {
    _id: targetFriend._id,
  },
  {
    $set: {
      [`friends.${currentUser._id.toString()}.friendshipStatus`]: null,
    },
  }
);

但是“$set”给我错误

Type '{ [x: string]: null; }' is not assignable to type 'Readonly<{ [x: `friends.${string}`]: unknown; [x: `friends.${string}.friendId`]: Friend | undefined; [x: `friends.${string}.friendshipStatus`]: Friend | undefined; [x: `friends.${string}.privateChannelId`]: Friend | undefined; [x: `friends.${string}.active`]: Friend | undefined;.
'string' and '`friends.${string}.friendId`' index signatures are incompatible.
Type 'null' is not assignable to type 'Friend | undefined'.

这个集合的接口是

interface User {
  name: string;
  discriminator: number;
  registerTime: Date;
  friends: Record<string, Friend>;
}

interface Friend {
  friendId: ObjectId;
  friendshipStatus?: FriendshipEnum | null;
  privateChannelId?: ObjectId;
  active?: boolean;
}
bvjxkvbb

bvjxkvbb1#

使用动态值作为字段名被认为是反模式,会给查询带来不必要的复杂性。但是,您可以使用$objectToArrayfriends转换为k-v对的数组。使用$map有条件地更新字段friendshipStatus。最后,使用$arrayToObject恢复为原始形式

db.collection.update({
  _id: ObjectId("63e501cc2054071132171098")
},
[
  {
    $set: {
      friends: {
        "$arrayToObject": {
          "$map": {
            "input": {
              "$objectToArray": "$friends"
            },
            "as": "f",
            "in": {
              "$cond": {
                "if": {
                  "$eq": [
                    "$$f.k",
                    "63e502f4e196ec7c04c4351e"
                  ]
                },
                "then": {
                  "$mergeObjects": [
                    "$$f",
                    {
                      v: {
                        "$mergeObjects": [
                          "$$f.v",
                          {
                            "friendshipStatus": 1
                          }
                        ]
                      }
                    }
                  ]
                },
                "else": "$$f"
              }
            }
          }
        }
      }
    }
  }
])

Mongo Playground
如果可以重构模式,可以考虑如下重构模式:

[
  {
    _id: ObjectId("63e501cc2054071132171098"),
    name: "Ricky",
    discriminator: 7706,
    registerTime: ISODate("2023-02-09T14:23:08.159Z"),
    friends: [
      {
        friendId: ObjectId("63e502f4e196ec7c04c4351e"),
        friendshipStatus: null,
        privateChannelId: ObjectId("63e66dd85eb6c3cc248ecc95"),
        active: true
      }
    ]
  }
]

您可以索引friends.friendId字段以提高性能。
查询可以变得简单得多:

db.collection.update({
  _id: ObjectId("63e501cc2054071132171098"),
  "friends.friendId": ObjectId("63e502f4e196ec7c04c4351e")
},
{
  $set: {
    "friends.$.friendshipStatus": 1
  }
})

Mongo Playground

相关问题