从MongoDB数组中删除不需要的元素并获取

总结

在MongoDB中,如果存在以下这样的数据,我们想要以原始结构的状态提取出仅没有设置删除标志的files数组,以下是相应的查询语句。

↓原始数据

[
  {
    "name": "testFile001",
    "createDate": ISODate("2022-08-01T12:34:56Z"),
    "createUser": "dora-chan",
    "files": [
      {
        "name": "file101",
        "delete": true,
        
      },
      {
        "name": "file102",
        
      },
      {
        "name": "file103",
        
      },
      
    ],
    
  },
  {
    "name": "testFile002",
    "createDate": ISODate("2022-08-02T12:34:56Z"),
    "createUser": "nobita",
    "files": [
      {
        "name": "file201",
        
      },
      {
        "name": "file202",
        "delete": true,
        
      },
      {
        "name": "file203",
        "delete": true,
        
      },
      
    ],
    
  },
  {
    "name": "testFile003",
    "createDate": ISODate("2022-08-03T12:34:56Z"),
    "createUser": "sizu-chan",
    "files": [
      {
        "name": "file301",
        "delete": true,
        
      },
      {
        "name": "file302",
        "delete": true,
        
      },
      {
        "name": "file303",
        "delete": true,
        
      },
      
    ],
    
  }
]

↓想要获取的数据

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "createDate": "createDate",
    "creteUser": "dora-chan",
    "files": [
      {
        "name": "file102"
      },
      {
        "name": "file103"
      }
    ],
    "name": "testFile001"
  },
  {
    "_id": ObjectId("5a934e000102030405000001"),
    "createDate": "createDate",
    "creteUser": "nobita",
    "files": [
      {
        "name": "file201"
      }
    ],
    "name": "testFile002"
  }
]

途径

在playGround中添加了示例。

在使用$unwind展开数组后,通过$match指定条件,并使用$group和$push将其重新装入数组中。

db.collection.aggregate([
  {
    $unwind: "$files" // 一旦files配列を展開する
  },
  {
    $match: {  // 展開した項目に対して条件指定
      "files.delete": {
        $ne: true
      }
    }
  },
  {
    $group: { // グルーピング
      _id: "$_id",
      createDate: {
        $first: "$createDate"
      },
      creteUser: {
        $first: "$createUser"
      },
      files: {
        $push: "$files" // 配列に詰め込む
      }
    }
  }
])

准备事项

关于allowDiskUse选项的内容。

使用此选项来覆盖 allowDiskUseByDefault 对于特定的查询。您可以使用此选项来执行以下操作之一:
在默认情况下允许使用磁盘的系统中禁止磁盘使用。
在默认情况下禁止使用磁盘的系统中允许磁盘使用。
从MongoDB 6.0开始,如果 allowDiskUseByDefault 设置为 true 并且服务器在管道执行阶段需要超过100兆字节的内存,MongoDB会自动将临时文件写入磁盘,除非查询指定{allowDiskUse:false}。
有关详细信息,请参阅allowDiskUseByDefault。
从MongoDB 4.2开始,分析器日志消息和诊断日志消息中将包含usedDisk指示符,如果由于内存限制而有任何聚合阶段写入数据到临时文件时。

DeepL翻译

使用此选项将覆盖allowDiskUseByDefault。通过使用此选项,可以执行以下操作之一。
在允许默认使用磁盘的系统中,禁止使用磁盘。
在默认禁止使用磁盘的系统中,允许使用磁盘。
从MongoDB 6.0开始,如果allowDiskUseByDefault设置为true,并且服务器在管道执行阶段需要超过100兆字节的内存,则除非在查询中指定{ allowDiskUse: false },否则MongoDB将自动将临时文件写入磁盘。
详细信息请参阅allowDiskUseByDefault。
自MongoDB 4.2起,配置文件器的日志消息和诊断日志消息中将显示usedDisk指示器,该指示器表示在聚合阶段由于内存限制而将数据写入临时文件的情况。

PlayGround没有提到,但是我的开发环境使用的是MongoDB4.4,并且在一个大量数据投入的环境中。如果不指定此选项,则会发生以下错误,通过添加选项,查询将得到通行。
根据我所知,MongoDB6.0以上版本默认为{ allowDiskUse: true },所以应该是不需要的。(未经验证)

{
	"message" : "Exceeded memory limit for $group, but didn't allow external sort. Pass allowDiskUse:true to opt in.",
	"ok" : 0,
	"code" : 292,
	"codeName" : "QueryExceededMemoryLimitNoDiskUseAllowed"
}
db.swp_clip.aggregate(
[
    {
        pipeline
    }
],
{
     allowDiskUse: true
}
)

关于$first

当进行分组时

  {
    $group: {
      _id: "$_id",
      createDate: "$createDate",
      creteUser: "$createUser",
      files: {
        $push: "$files"
      }
    }
  }

尝试时出现了以下错误。

query failed: (Location40234) The field 'creteUser' must be an accumulator object

为了进行分组,需要将其统一为单个值,因此使用$first来获取第一个值(实际上它们都是相同的,所以无论哪个都可以)。

请参考Group Accumulator Operators以获取更详细信息。

广告
将在 10 秒后关闭
bannerAds