You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose查询结果过滤异常:误删归属正确的instances对象

问题需求与异常现象

我通过Mongoose的find查询得到一个展览对象数组,结构如下(每个展览包含artworks数组,每个艺术品又包含instances数组):

let exhibitions = [
    {
      "_id": "63047848edbb342f6805166e",
      "name":"Exhibition1",         
      "artworks": [
          {
            "_id": "6303519929e74916708b508b",             
            "instances": [
                {
                  "_id": "630486e2a13932fa8e2ff4b5",
                  "parentID": "6303519929e74916708b508b",
                  "exhibitionID": "63047848edbb342f6805166e",
                  "HangLineID": "555",
                },
                {
                  "_id": "630486e2a13932fa8e2ff4b5",
                  "parentID": "6303519929e74916708b508b",
                  "exhibitionID": "63047848edbb342f6805166e",
                  "HangLineID": "444",
                },
            ]
          },
          {
           "_id": "6304878ba13932fa8e2ff4d9",
            "instances": [
                {
                  "_id": "6308377d7c60564627494e16",
                  "parentID": "6304878ba13932fa8e2ff4d9",
                  "exhibitionID": "6304dbfb2af05390425969f7",
                  "HangLineID": "333",
                }
            ]           
          },               
      ],         
    },
    {           
      "_id": "6304dbfb2af05390425969f7", 
      "name":"Exhibition2",         
      "artworks": [
          {
            "_id": "62f20e22dc17b1712596016a",                  
            "instances": [
                {
                  "_id": "6304dc672af0539042596a07",
                  "parentID": "62f20e22dc17b1712596016a",
                  "exhibitionID": "6304dbfb2af05390425969f7",
                  "HangLineID": "000",
                  "HangLineArtworkArrayPosition": 2,
                  "__v": 0
                }
            ]
          }
      ]
    }
]

需求是:移除instances中exhibitionID与所属展览_id不匹配的元素(两者均为Mongoose ObjectId类型)。

尝试用Lodash的remove方法实现时,成功移除了Exhibition1中不符合的实例,但误删了Exhibition2中归属正确的实例。我的代码如下:

exhibitions.map((exh, key)=>{ 
  const artworks = exh.artworks;
  artworks.map((artwork,index1) =>{
    const instances = artwork.instances
    _.remove(
      instances, 
      v => (
        v.exhibitionID.toString()!=(exh._id).toString())            
      )})
      
    })

经测试,v.exhibitionID.toString()!==(exh._id).toString()的条件判断输出是正确的;改用v.HangLineID!="555"时能正常过滤,怀疑是对象比较逻辑的问题?


问题分析与解决方案

核心问题:闭包变量引用导致的循环异常

你用map遍历artworks时,内部的_.remove回调里引用了外部的exh变量,但由于JavaScript闭包的特性,当循环执行到后期时,回调里的exh可能已经指向数组的最后一个元素(也就是Exhibition2),导致所有instances都用最后一个展览的_id做判断,从而误删Exhibition2中原本符合条件的实例。

修复方案

可以通过以下两种方式解决:

方案1:用forEach替代map(避免闭包引用问题)

map的设计目的是返回新数组,这里我们只是要修改原数组,用forEach更合适,同时也能避免闭包变量的引用异常:

exhibitions.forEach(exh => {
  exh.artworks.forEach(artwork => {
    const currentExhId = exh._id.toString();
    _.remove(artwork.instances, v => v.exhibitionID.toString() !== currentExhId);
  });
});

方案2:提前缓存当前展览的ID,避免闭包引用

如果坚持用map,可以提前把当前展览的ID转成字符串缓存起来,确保回调里用的是当前循环的ID:

exhibitions.map(exh => { 
  const currentExhId = exh._id.toString();
  exh.artworks.map(artwork => {
    _.remove(artwork.instances, v => v.exhibitionID.toString() !== currentExhId);
  });
  return exh; // map需要返回元素,否则会生成全为undefined的数组
});

额外优化:用Mongoose内置方法比较ObjectId

Mongoose的ObjectId本身提供了equals方法,可以直接用来比较,不需要转字符串,这样更可靠:

// 用equals方法替代toString比较
_.remove(artwork.instances, v => !v.exhibitionID.equals(exh._id));

内容的提问来源于stack exchange,提问作者Miss_scare_all

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:16:00