如何将每个数组字段与MongoDB中的其他字段匹配

Posted

技术标签:

【中文标题】如何将每个数组字段与MongoDB中的其他字段匹配【英文标题】:How to match each array field to other field in Mongodb 【发布时间】:2020-04-18 12:09:32 【问题描述】:

我有一个数组如下:

const test = [
    "_id": 1,
    "name": "apple",
    "car": "ford"
,
    "_id": 2,
    "name": "melon",
    "car": "ferrari"
,
    "_id": 3,
    "name": "perl",
    "car": "Renaut"
]

还有Mongodb的文档如下:

[
  "name": "perl", "company": "A"
,
  "name": "melon", "company": "B"
,
  "name": "apple", "company": "C"
,
  "name": "apple", "company": "D"
,
  "name": "perl", "company": "E"
,
  "name": "apple", "company": "F"
]

我想使用 mongodb 聚合得到这个结果:

[
  "name": "perl", "company": "A", testInform:  "_id": 3, "name": "perl", "car": "Renaut"
,
  "name": "melon", "company": "B", testInform:  "_id": 2, "name": "melon", "car": "ferrari"
,
  "name": "apple", "company": "C", testInform:  "_id": 1, "name": "apple", "car": "ford"
,
  "name": "apple", "company": "D", testInform:  "_id": 1, "name": "apple", "car": "ford"
,
  "name": "perl", "company": "E", testInform:  "_id": 3, "name": "perl", "car": "Renaut"
,
  "name": "apple", "company": "F", testInform:  "_id": 1, "name": "apple", "car": "ford"
]

我想将聚合与$match$facet 等一起使用,但我不知道具体该怎么做。你能推荐一个解决方案吗?

非常感谢您阅读本文。

【问题讨论】:

【参考方案1】:

$lookup 带有管道关键字

db.demo2.aggregate(
    
      $lookup:
         
           from: "demo1",
           let:  recordName: "$name",
           pipeline: [
               $match:
                  $expr:
                     $and:
                       [
                          $eq: [ "$$recordName",  "$name" ] ,
                       ]
                    
                 
              ,
           ],
           as: "testInform"
         

    
    )

【讨论】:

【参考方案2】:

如果 test 数组数据存储在集合中,那么通过 $lookup 聚合实现 O/P 非常简单

$arrayElemAt 为什么?因为查找将在数组中以testInform 的形式获取连接的文档

db.maindocs.aggregate([
  
    $lookup: 
      from: "testdocs",
      localField: "name",
      foreignField: "name",
      as: "testInform"
    
  ,
  
    $project: 
      _id: 0,
      name: 1,
      company: 1,
      testInform:  $arrayElemAt: ["$testInform", 0] 
    
  
]);

基于 cmets 的更新:

想法是从存储在 mongodb 中的文档中迭代 cursor Array.prototype.find() 来自 test 的与 name 字段匹配的对象,将其添加到结果中。

const test = [
  
    _id: 1,
    name: "apple",
    car: "ford"
  ,
  
    _id: 2,
    name: "melon",
    car: "ferrari"
  ,
  
    _id: 3,
    name: "perl",
    car: "Renaut"
  
];


const cursor = db.collection("maindocs").find();
const result = [];

while (await cursor.hasNext()) 
  const doc = await cursor.next();
  const found = test.find(e => e.name === doc.name);
  if (found) 
    doc["testInform"] = found;
  
  result.push(doc);


console.info("RESULT::", result);

【讨论】:

测试数组未存储在集合中。它只是js中的常量值。您能否为此推荐其他解决方案? @DDDD 已经用另一个解决方案更新了答案。看看它是否适合你。 注意:我在这里使用了async/await 语法,如果这不是您使用的,可以使用callback 样式和forEach 更改迭代。但逻辑保持不变。【参考方案3】:

聚合有一个阶段:遍历test 数组并获取数组元素作为匹配文档和数组中的name 字段的对象(使用$reduce 运算符)。

const test = [  ... , ... ]

db.test_coll.aggregate( [
   
      $addFields:  
          testInform:  
              $reduce: 
                  input: test,
                  initialValue:  ,
                  in: 
                      $cond: [  $eq: [ "$$this.name", "$name" ] , 
                                $mergeObjects: [ "$$this", "$$value" ] , 
                               "$$value"
                             ]
                      
               
          
      
  
] )

【讨论】:

以上是关于如何将每个数组字段与MongoDB中的其他字段匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何匹配 MongoDB 中的子文档数组?

如何将集合的字段与另一个集合的数组内的字段匹配

如何匹配MongoDB中的子文档数组?

如何根据MongoDB中文档字段中的每个数组项过滤集合

MongoDB 更新数组数组中的文档字段

如何使用 mongoose 和 NodeJs 在 Mongodb 的数组字段中插入数据