MongoDB 过滤数组中的特定数据并仅返回输出中的特定字段

vas*_*jan 5 mongodb mongodb-query aggregation-framework

我在样本集合中维护了以下结构。

{
  "_id": "1",
  "name": "Stock1",
  "description": "Test Stock",
  "lines": [
    {
      "lineNumber": "1",
      "priceInfo": {
        "buyprice": 10,
        "sellprice": 15
      },
      "item": {
        "id": "BAT10001",
        "name": "CricketBat",
        "description": "Cricket bat"
      },
      "quantity": 10
    },
    {
      "lineNumber": "2",
      "priceInfo": {
        "buyprice": 10,
        "sellprice": 15
      },
      "item": {
        "id": "BAT10002",
        "name": "CricketBall",
        "description": "Cricket ball"
      },
      "quantity": 10
    },
    {
      "lineNumber": "3",
      "priceInfo": {
        "buyprice": 10,
        "sellprice": 15
      },
      "item": {
        "id": "BAT10003",
        "name": "CricketStumps",
        "description": "Cricket stumps"
      },
      "quantity": 10
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我有一个场景,我将获得lineNumberand item.id,我需要根据lineNumberand过滤上述集合,item.id并且我只需要投影选定的字段。

预期输出如下:

{
  "_id": "1",
  "lines": [
    {
      "lineNumber": "1",
      "item": {
        "id": "BAT10001",
        "name": "CricketBat",
        "description": "Cricket bat"
      },
      "quantity": 10
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

注意:我可能不会每次lineNumber都得到,如果lineNumber为空,那么我应该item.id单独过滤并获得上述输出。主要目的是减少输出中的字段数量,因为集合预计将容纳大量领域。

我尝试了以下查询,

db.sample.aggregate([
{ "$match" : { "_id" : "1"} ,
{ "$project" : { "lines" : { "$filter" : { "input" : "$lines" , "as" : "line" , "cond" : 
    { "$and" : [ { "$eq" : [ "$$line.lineNumber" , "3"]} , { "$eq" : [ "$$line.item.id" , "BAT10001"]}]}}}}}
])
Run Code Online (Sandbox Code Playgroud)

但是我得到了所有字段,我无法排除或包含必填字段。

vas*_*jan 7

我尝试了以下查询,它对我有用,

db.Collection.aggregate([
{ $match: { _id: '1' } },
{
  $project: {
    lines: {
      $map: {
        input: {
          $filter: {
            input: '$lines',
            as: 'line',
            cond: {
              $and: [
                { $eq: ['$$line.lineNumber', '3'] },
                { $eq: ['$$line.item.id', 'BAT10001'] },
              ],
            },
          },
        },
        as: 'line',
        in: {
          lineNumber: '$$line.lineNumber',
          item: '$$line.item',
          quantity: '$$line.quantity',
        },
      },
    },
  },
},
Run Code Online (Sandbox Code Playgroud)

])


Neo*_*dan 4

您可以通过$unwind$group聚合阶段来实现它:

db.collection.aggregate([
    {$match: {"_id": "1"}},
    {$unwind: "$lines"},
    {$match: {
        $or: [
            {"lines.lineNumber":{$exists: true, $eq: "1"}},
            {"item.id": "BAT10001"}
        ]
    }},
    {$group: {
        _id: "$_id",
        lines: { $push: {
            "lineNumber": "$lines.lineNumber",
            "item": "$lines.item",
            "quantity": "$lines.quantity"
        }}
    }}
])
Run Code Online (Sandbox Code Playgroud)
  • $match - 设置文档过滤器的条件。第一阶段是获取_id=“1”的文档,第二阶段仅获取等于lines.lineNumber“1”或item.id等于“BAT10001”的文档。
  • $unwind - 将lines数组拆分为单独的文档。
  • $group - 按元素合并文档_id,并将生成的对象与lineNumber,itemquantity元素放入lines数组中。