MongoDB updateOne($pull) 匹配一个文档,但没有从数组中删除它

Posted

技术标签:

【中文标题】MongoDB updateOne($pull) 匹配一个文档,但没有从数组中删除它【英文标题】:MongoDB updateOne($pull) is matching a document, but not removing it from an arrayMongoDB updateOne($pull) 匹配一个文档,但没有从数组中删除它 【发布时间】:2021-03-03 04:23:37 【问题描述】:

我正在构建一个基于 Pokemon API MERN 的应用程序,用户可以在其中从搜索组件搜索 Pokemon 并将它们添加到他们的个人资料中。用户模式包含一个口袋妖怪数组,其中每个口袋妖怪都由一个包含 Pokedex 编号、口袋妖怪名称和精灵源链接数组的文档表示,以便每个口袋妖怪都可以映射到用户的配置文件。我正在使用 $push 运算符将搜索结果中的每个口袋妖怪从 put 请求中添加到用户的团队中,效果很好。就像在实际游戏中一样,每个用户一次只能在他们的团队中拥有 6 个口袋妖怪,但是一个用户的团队也可以包含相同口袋妖怪的副本,所以为了从用户的团队中删除口袋妖怪,我发送了一个 put请求当前登录用户的用户名以及要删除的口袋妖怪的_id。当我尝试这个请求时,它返回一个错误,说 n:1 已经匹配,但是文档不是从用户的口袋妖怪数组中提取的。

router.put("/del", auth, async (req, res) => 
  // Find user
  User.findOne( username: req.body.username ).then((user) => 
    // Try updating Pokemon array
    const offTeam = user
      .updateOne( $pull:  pokemon:  _id: req.body.id   , function(
        err,
        data
      ) 
        console.log("ERROR:", err, data, err.message);
      )
      .then((offTeam) => 
        res.status(200).json(offTeam);
      )
      .catch((e) => 
        return res.status(400).json( msg: e.message );
      );
  );
);

下面是返回的错误:

ERROR: null 
  n: 1,
  nModified: 0,
  opTime: 
    ts: Timestamp  _bsontype: 'Timestamp', low_: 2, high_: 1605810353 ,
    t: 4
  ,
  electionId: 7fffffff0000000000000004,
  ok: 1,
  '$clusterTime': 
    clusterTime: Timestamp  _bsontype: 'Timestamp', low_: 2, high_: 1605810353 ,
    signature:  hash: [Binary], keyId: [Long] 
  ,
  operationTime: Timestamp  _bsontype: 'Timestamp', low_: 2, high_: 1605810353 

编辑:链接到存储库,当前在删除分支中工作。 https://github.com/nrhill1/pokeMERN/tree/delete

编辑:这是我的个人资料示例。我正在尝试删除 Marill 和 Houndoom,但都不会删除。

    _id
    :5fb5ef14e664d5172ee5e1ed
    username
    :"nic"
    email
    :"nic@gmail.com"
    password
    :"$2a$10$kKfpdkmPMeWAS.22nulCSOkVeqKPGxiA5PL9D5WhPsU0pAznq/J2u"
    pokemon
    :
    Array
        0
        :
        Object
            _id
            :5fb5ef26e664d5172ee5e1ee
            id
            :229
            name
            :"houndoom"
            sprites
            :
            Array
        1
        :
        Object
            _id
            :5fb614318558521aac650a4c
            id
            :183
            name
            :"marill"
            sprites
            :
            Array
                0
                :"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokem..."
                1
                :"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokem..."
    reg_date
    :2020-11-19T04:05:40.436+00:00
    __v
    :0

【问题讨论】:

您能发布一个文档示例和预期输出吗? @J.F.编辑了帖子并添加了我的用户资料 【参考方案1】:

您可以使用$in 并将您想要拉入的 id 设置为这样的数组(如果您想添加更多元素,我认为这是未来最简单的方法):

db.collection.update(
  "_id": "5fb5ef14e664d5172ee5e1ed",
,

  "$pull": 
    "pokemon": 
      "id": 
        "$in": [
          229,
          183
        ]
      
    
  
,

  "multi": true
)

查询首先匹配_id(我猜是用户ID,但如果需要,您可以使用usernameemail 或其他字段)然后拉出所有id 在数组内的口袋妖怪。在这种情况下,229183 将被删除。 示例here

请注意,如果您使用方法updateMany(),则不需要multi:true

使用猫鼬是相同的查询,但使用updateMany()

var idToUpdate = mongoose.Types.ObjectId(req.body.id)
var pokemonsToDelete = [229, 183]
var updated = await model.updateMany(
  "_id": idToUpdate,
,

  "$pull": 
    "pokemon": 
      "id": 
        "$in": pokemonsToDelete
      
    
  
)

【讨论】:

尝试将req.body.id解析为ObjectId。像这样的东西:mongoose.Types.ObjectId(req.body.id) 我已经测试过了,它对我有用。也许你错过了分享任何可能改变查询或任何缺失值的东西? 好的,所以我认为您误读了我原来的问题。我不能使用 pokedex 编号,因为这样它就不允许用户删除他们团队中重复的 pokemon 的副本。如果我想要一个由所有皮卡丘组成的团队,只要我只想删除一个皮卡丘,这个查询就会删除每个皮卡丘。 所以你想被pokemon _id删除?然后用这个字段代替id 不费吹灰之力!非常感谢你的帮助。解决方法是将 _id 包装在 mongoose.Types.ObjectId(_id) 中。

以上是关于MongoDB updateOne($pull) 匹配一个文档,但没有从数组中删除它的主要内容,如果未能解决你的问题,请参考以下文章

mongoose updateOne 功能:如果 $pull 不起作用则不更新

MongoDB中updateOne超过findOneAndUpdate的用例[重复]

MongoDB updateOne查询计算

在 MongoDB 中使用 updateOne 时如何访问 upsertedId

mongodb:如果元素不存在,则updateOne设置字符串数组,如果存在则保持不变

带有嵌入式文档的MongoDB findOne()和updateOne()