Mongodb 聚合使用ID的文档填充ID数组

Mongodb 聚合使用ID的文档填充ID数组,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我正在使用mongodb中的一些聚合函数。 我想在作者的文档中获取books文档,该文档只有books ID作为字符串数组ID,如下所示: 作者文档 { "_id" : "10", "full_name" : "Joi Dark", "books" : ["100", "200", "351"], } 和其他文件(书籍): 因此,我希望这样: { "_id" : "10", "full_name" : "Joi Dark", "books" : [ {

我正在使用mongodb中的一些聚合函数。 我想在作者的文档中获取books文档,该文档只有books ID作为字符串数组ID,如下所示:

作者文档

{
  "_id" : "10",
  "full_name" : "Joi Dark",
  "books" : ["100", "200", "351"],
}
和其他文件(书籍):

因此,我希望这样:

{
  "_id" : "10",
  "full_name" : "Joi Dark",
  "books" : [
       {
           "_id" : "100",
           "title" : "Node.js In Action",
           "ISBN" : "121215151515154",
           "date" : "2015-10-10"
       },
       {
           "_id" : "200",
           "title" : "Book 2",
           "ISBN" : "1212151454515154",
           "date" : "2015-10-20"
       },
       {
           "_id" : "351",
           "title" : "Book 3",
           "ISBN" : "1212151454515154",
           "date" : "2015-11-20"
       }
  ],
}
用于根据
本地字段
外来字段
的匹配,从
中的指定集合中检索数据:

db.authors.aggregate([
  { "$lookup": {
    "from": "$books",
    "foreignField": "_id",
    "localField": "books",
    "as": "books"
  }}
])
as
是在文档中写入包含相关文档的“数组”的位置。如果指定现有属性(如此处所述),则输出中的新数组内容将覆盖该属性

如果您在MongoDB 3.4之前有一个MongoDB,那么您可能需要首先将
“books”
数组设置为
本地字段

db.authors.aggregate([
  { "$unwind": "$books" },
  { "$lookup": {
    "from": "$books",
    "foreignField": "_id",
    "localField": "books",
    "as": "books"
  }}
])
它为原始文档中的每个数组成员创建一个新文档,因此再次使用和创建原始表单:

db.authors.aggregate([
  { "$unwind": "$books" },
  { "$lookup": {
    "from": "$books",
    "foreignField": "_id",
    "localField": "books",
    "as": "books"
  }},
  { "$unwind": "$books" },
  { "$group": {
    "_id": "$_id",
    "full_name": { "$first" "$full_name" },
    "books": { "$push": "$books" }
  }}
])
如果事实上您的
\u id
值位于
ObjectId
类型的外部集合中,但
localField
中的值是该类型的“字符串”版本,则需要转换数据以使类型匹配。没有别的办法

在shell中运行类似以下内容以转换:

var ops = [];
db.authors.find().forEach(doc => {
  doc.books = doc.books.map( book => new ObjectId(book.valueOf()) );

  ops.push({
    "updateOne": {
      "filter": { "_id": doc._id },
      "update": {
        "$set": { "books": doc.books }
      }
    }
  });

  if ( ops.length >= 500 ) {
    db.authors.bulkWrite(ops);
    ops = [];
  }
});

if ( ops.length > 0 ) {
  db.authors.bulkWrite(ops);
  ops = [];
}

这将把
“books”
数组中的所有值转换为真正的
ObjectId
值,这些值在
$lookup
操作中可以实际匹配。

如果不起作用,请返回空数组。books文档有_id键入的ObjectId,但在authors文档中,我只将id保存为字符串。@JahangirAhmad那么您需要修复它。您的问题在两个字段中都显示“字符串”。因此,请修复您的数据,使“object id like”字符串实际成为
ObjectId
值。你需要帮助吗?请更新您的问题以显示真实数据。我所说的“更新”是指“除此之外”,不要覆盖您在原始问题中输入的数据。所以我把你的复习卷退了。得到答案后,不要更改所问问题的上下文。@JahangirAhmad您无法将字符串与
对象ID
匹配。您需要帮助了解如何转换它们吗?如果你这样做了,那就问。停止编辑问题。是,请帮助我转换that@JahangirAhmad为运行转换添加了一个shell脚本。
var ops = [];
db.authors.find().forEach(doc => {
  doc.books = doc.books.map( book => new ObjectId(book.valueOf()) );

  ops.push({
    "updateOne": {
      "filter": { "_id": doc._id },
      "update": {
        "$set": { "books": doc.books }
      }
    }
  });

  if ( ops.length >= 500 ) {
    db.authors.bulkWrite(ops);
    ops = [];
  }
});

if ( ops.length > 0 ) {
  db.authors.bulkWrite(ops);
  ops = [];
}