如何在 mongoDB 中使用多结果聚合/查找?

How to use aggregation/ lookup in mongoDB with multi results?

我下面有一个“图片”集合(注意:labels字段是一个数组,因为1张图片可能有很多标签)

{
    "_id" : ObjectId("624d182b6a4e7f001ed5cd9f"),
    "is_deleted" : false,
    "labels" : [ 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69c"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.440625,
            "xmax" : 0.2953125,
            "ymin" : 0.102083333333333,
            "ymax" : 0.366666666666667
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69d"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.2546875,
            "xmax" : 0.45,
            "ymin" : 0.220833333333333,
            "ymax" : 0.439583333333333
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69e"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.240625,
            "xmax" : 0.48125,
            "ymin" : 0.208333333333333,
            "ymax" : 0.466666666666667
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69f"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.275618374558304,
            "xmax" : 0.436395759717314,
            "ymin" : 0.136470588235294,
            "ymax" : 0.404705882352941
        }
    ],
    "img_name" : "6917328478506479617.jpg",
    "img_originalname" : "frame27406302021-085850.jpg",
    "img_desc" : "Cyber Sercurity multi upload",
    "img_uri" : "http://localhost:8080/resources/images/2022/4/6/6917328478506479617.jpg",
    "img_path" : "/resources/images/2022/4/6/6917328478506479617.jpg",
    "datasetId" : ObjectId("624d14216a4e7f001ed5c459"),
    "createdAt" : ISODate("2022-04-06T04:33:47.120Z"),
    "updatedAt" : ISODate("2022-05-10T07:09:48.306Z"),
    "__v" : 0
}

下面是“标签”集合:

{
    "_id" : ObjectId("624d14d76a4e7f001ed5c6ca"),
    "is_deleted" : false,
    "labelName" : "Đông",
    "description" : "qw",
    "datasetId" : ObjectId("624d14216a4e7f001ed5c459"),
    "createdAt" : ISODate("2022-04-06T04:19:35.985Z"),
    "updatedAt" : ISODate("2022-04-06T04:19:35.985Z"),
    "__v" : 0,
    "datanoiseId" : ObjectId("6261318b23a7a590480f92e6")
}

现在我想查找将有关标签的所有信息加入到图像中,所以我这样做了:

db.Image.aggregate([
  {
       $match: {
           $and: [{"datasetId": ObjectId("624d14216a4e7f001ed5c459"), "is_deleted": false}]
       }
   },
  {
    $lookup: {
      from: "Label",
      localField: "labels.labelId",
      foreignField: "_id",
      as: "labelDocuments",
    },
  },
  
  { $sort : { "_id" : -1 } }
])

执行上述查询后得到的结果如下:

{
    "_id" : ObjectId("624d182b6a4e7f001ed5cd9f"),
    "is_deleted" : false,
    "labels" : [ 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69c"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.440625,
            "xmax" : 0.2953125,
            "ymin" : 0.102083333333333,
            "ymax" : 0.366666666666667
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69d"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.2546875,
            "xmax" : 0.45,
            "ymin" : 0.220833333333333,
            "ymax" : 0.439583333333333
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69e"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.240625,
            "xmax" : 0.48125,
            "ymin" : 0.208333333333333,
            "ymax" : 0.466666666666667
        }, 
        {
            "_id" : ObjectId("627a0fbc12458800209dd69f"),
            "labelId" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "xmin" : 0.275618374558304,
            "xmax" : 0.436395759717314,
            "ymin" : 0.136470588235294,
            "ymax" : 0.404705882352941
        }
    ],
    "img_name" : "6917328478506479617.jpg",
    "img_originalname" : "frame27406302021-085850.jpg",
    "img_desc" : "Cyber Sercurity multi upload",
    "img_uri" : "http://localhost:8080/resources/images/2022/4/6/6917328478506479617.jpg",
    "img_path" : "/resources/images/2022/4/6/6917328478506479617.jpg",
    "datasetId" : ObjectId("624d14216a4e7f001ed5c459"),
    "createdAt" : ISODate("2022-04-06T04:33:47.120Z"),
    "updatedAt" : ISODate("2022-05-10T07:09:48.306Z"),
    "__v" : 0,
    "labelDocuments" : [ 
        {
            "_id" : ObjectId("624d14d76a4e7f001ed5c6ca"),
            "is_deleted" : false,
            "labelName" : "Đông",
            "description" : "qw",
            "datasetId" : ObjectId("624d14216a4e7f001ed5c459"),
            "createdAt" : ISODate("2022-04-06T04:19:35.985Z"),
            "updatedAt" : ISODate("2022-04-06T04:19:35.985Z"),
            "__v" : 0,
            "datanoiseId" : ObjectId("6261318b23a7a590480f92e6")
        }
    ]
}

你看,labels字段有4条记录,而labelDocuments字段只有1条记录?原因是我给图片赋标签的时候,给1张图片赋了很多标签(labelId相同),所以lookup命令只能join 1条记录?那么在这种情况下如何使“labelDocuments 有 4 个记录相同的”标签“字段?请帮助我,谢谢

$lookup操作可以获得多条记录。在您的数据中,您只有一个 (ObjectId("624d14d76a4e7f001ed5c6ca")),您的所有标签都引用了它。这就是您在 labelDocuments 数组中只获得一个文档的原因。

如果您的目标是合并标签,您可以添加查询步骤:

{
    $addFields: {
      mergedLabels: {
        $map: {
          input: "$labels",
          as: "i",
          in: {
            $mergeObjects: [
              "$$i",
              {
                $first: {
                  $filter: {
                    input: "$labelDocuments",
                    cond: {
                      $eq: [
                        "$$this._id",
                        "$$i.labelId"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
 {
    $unset: ["labelDocuments", "labels"]
  },

像这个例子:playground 1 这是基于@turivishal

如果你想把它们放在一个新数组中,就像你说的,你可以改为添加:

  {
    $addFields: {
      labelDocuments: {
        $map: {
          input: "$labels",
          as: "i",
          in: {
            $mergeObjects: [
              {},
              {
                $first: {
                  $filter: {
                    input: "$labelDocuments",
                    cond: {
                      $eq: [
                        "$$this._id",
                        "$$i.labelId"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },

playground 2.

如果您想将标签保留在图像文档下,最好不要 $unwind,因为这将是一项代价高昂的冗余操作,但正如我所说,这取决于您接下来要做什么。

你应该先放松一下。

db.Image.aggregate([{
    $match: {
      $and: [{
        "datasetId": ObjectId("624d14216a4e7f001ed5c459"),
        "is_deleted": false
      }]
    }
  },

  {
    $unwind: "$lables"
  },
  {
    $lookup: {
      from: "Label",
      localField: "labels.labelId",
      foreignField: "_id",
      as: "labelDocuments",
    },
  },

  {
    $sort: {
      "_id": -1
    }
  }
])