ดึงเอกสารที่ตรงกันจากอาร์เรย์ที่ซ้อนกัน [ซ้ำกัน]

ฉันกำลังพยายามรวบรวมวัตถุทั้งหมดในอาร์เรย์ที่ซ้อนกันโดยที่ฟิลด์ spec เท่ากับ unknown

โครงสร้างต่อเอกสารจะคล้ายกับสิ่งนี้:

{
    "_id" :"5b1e73786f11e421956023c3",
    "subs" : [ 
        {
            "name" : "subrepo1",
            "files" : [ 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }
            ]
        },
        {
            "name" : "subrepo2",
            "files" : [ 
                {
                    "name" : "file2",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "1234"
                }
            ]
        }
    ]
}

ฉันลองทำสิ่งต่อไปนี้แล้ว แต่มันไม่ทำงาน ฉันคิดว่านี่เป็นไปในทิศทางที่ถูกต้อง แต่ฉันอาจพลาดบางสิ่งที่สำคัญไป

db.col.aggregate([
    {$match: {'subs.files.spec': 'Unknown'}},
    {$project: {
        'subs.files': {$filter: {
            input: '$subs.files',
            //as: 'subs.files',
            cond: {$eq: ['this.spec', 'FunSuite']}
        }},
        //_id: 0
    }}
])

ผลลัพธ์ที่คาดหวังจะเป็น: (ดังนั้นเฉพาะไฟล์ที่มี spec เท่ากับ Unknown (ไม่ใช่ไฟล์อื่น)

{
    "_id" : "5b1e73786f11e421956023c3",
    "subs" : [ 
        {
            "name" : "subrepo1",
            "files" : [ 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }, 
                {
                    "name" : ".....",
                    "spec" : "Unknown"
                }
            ]
        },
        {
            "name" : "subrepo2",
            "files" : [ 
                {
                    "name" : "file2",
                    "spec" : "Unknown"
                }
            ]
        }
    ]
}

person Captain Obvious    schedule 12.06.2018    source แหล่งที่มา
comment
ผลลัพธ์ที่คุณคาดหวังคืออะไร?   -  person Mạnh Quyết Nguyễn    schedule 12.06.2018
comment
@ MnhQuyếtNguyễn เพิ่มผลลัพธ์เพื่อให้ชัดเจน   -  person Captain Obvious    schedule 12.06.2018


คำตอบ (2)


คุณต้องใช้ตัวดำเนินการ $filter aggregation ซึ่ง ให้เฉพาะองค์ประกอบที่ตรงกันจากอาร์เรย์และหลีกเลี่ยงองค์ประกอบอื่นๆ

db.collection.aggregate([
  {
    $unwind: "$subs"
  },
  {
    $project: {
      "subs.name": "$subs.name",
      "subs.files": {
        $filter: {
          input: "$subs.files",
          as: "file",
          cond: {
            $eq: [
              "$$file.spec",
              "Unknown"
            ]
          }
        }
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      subs: {
        $push: "$subs"
      }
    }
  }
])

ด้านบนจะให้ผลลัพธ์ต่อไปนี้

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "subs": [
      {
        "files": [
          {
            "name": ".....",
            "spec": "Unknown"
          },
          {
            "name": ".....",
            "spec": "Unknown"
          }
        ],
        "name": "subrepo1"
      },
      {
        "files": [
          {
            "name": "file2",
            "spec": "Unknown"
          }
        ],
        "name": "subrepo2"
      }
    ]
  }
]

คุณสามารถตรวจสอบผลลัพธ์ได้ที่นี่

และหากคุณต้องการรับฟิลด์เหมือนในอาร์เรย์ ให้ลบ $unwind และ $replaceRoot จากไปป์ไลน์

db.collection.aggregate([
  {
    $unwind: "$subs"
  },
  {
    $project: {
      "subs.name": "$subs.name",
      "subs.files": {
        $filter: {
          input: "$subs.files",
          as: "file",
          cond: {
            $eq: [
              "$$file.spec",
              "Unknown"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$subs.files"
  },
  {
    $replaceRoot: {
      newRoot: "$subs.files"
    }
  }
])

ด้านบนจะให้ผลลัพธ์ต่อไปนี้

[
  {
    "name": ".....",
    "spec": "Unknown"
  },
  {
    "name": ".....",
    "spec": "Unknown"
  },
  {
    "name": "file2",
    "spec": "Unknown"
  }
]
person Ashh    schedule 12.06.2018
comment
นี่ไม่ใช่ข้อมูลอินพุตเดียวกับที่ให้ไว้ในตัวอย่าง คุณเปลี่ยนได้ไหม (ผลงานออกมาดี) - person Captain Obvious; 12.06.2018
comment
@CaptainObvious ฉันมีการเปลี่ยนแปลงอินพุตและเอาต์พุต ... โปรดตรวจสอบอีกครั้ง ... - person Ashh; 12.06.2018
comment
ดูเหมือนว่าจะได้ผล ขอบคุณ. คุณสามารถระบุแบบสอบถามสำหรับผลลัพธ์ต้นฉบับของคุณได้หรือไม่ ผลลัพธ์จะมีเฉพาะไฟล์ {name: ..., spec: ....} เพราะฉันก็อยากได้มันเหมือนกัน ฉันจะยอมรับหากคุณรวมอันนั้นด้วย - person Captain Obvious; 12.06.2018

ลองวิธีนี้:

db.col.aggregate([
    {
        $unwind: '$subs'
    },
    {
        $unwind: '$subs.files'
    },
    {
        $match: {
            'subs.files.spec': 'Unknown'
        }
    }
]);
person karaxuna    schedule 12.06.2018
comment
นอกจากนี้ยังส่งคืนองค์ประกอบในอาร์เรย์ไฟล์โดยที่สเป็คไม่เท่ากับไม่ทราบ ซึ่งฉันไม่ต้องการ (ดูผลลัพธ์) - person Captain Obvious; 12.06.2018