MongoDB 查找给出了正确的输出但没有更新 collection

MongoDB lookup gives correct output but doesn't update collection

我有以下 collections:

phones:

{"_id": {
    "$oid": "61d376c0b9887d4e736e6acb"
},
"brand": "Nokia",
"name": "Nokia 3210",
"picture": "https://fdn2.gsmarena.com/vv/bigpic/no3210b.gif",
"phoneId": "1" }

评论:

{"_id": {
    "$oid": "61d333d0ac2d25f88d0bc8fa"
},
"phoneId": "1",
"rating": "3",
"dateOfReview": {
    "$date": "2008-11-18T00:00:00.000Z"
},
"title": "Ok phone to tide me over",
"userId": "47599" }

我 运行 在 MongoCompass 和 MongoShell 上进行了以下聚合,并给出了预期的结果:

db.phones.aggregate([{$lookup: {
 from: 'reviews',
 localField: 'phoneId',
 foreignField: 'phoneId',
 as: 'reviews'
}}])

{ _id: ObjectId("61d376c0b9887d4e736e6acb"),
  brand: 'Nokia',
  name: 'Nokia 3210',
  picture: 'https://fdn2.gsmarena.com/vv/bigpic/no3210b.gif',
  phoneId: '1',
  reviews: 
   [ { _id: ObjectId("61d333d0ac2d25f88d0bc8fa"),
       phoneId: '1',
       rating: '3',
       dateOfReview: 2008-11-18T00:00:00.000Z,
       title: 'Ok phone to tide me over',
       userId: '47599' } ] }

但是当我查看collection没有字段评论时,如何才能将其永久添加到collection?因为我对每个 phone 都有很多评论,所以我还想在 phone 中的评论数组中添加只有 20 个与 phoneId 匹配的最新评论,是吗?可能吗?

您可以使用 $merge and $out 管道阶段将数据写回您的数据库。

请注意,这些阶段必须是管道中的最后阶段。

例如

db.phones.aggregate([
  {
    $lookup: {
      from: 'reviews',
      localField: 'phoneId',
      foreignField: 'phoneId',
      as: 'reviews'
    }
  },
  {
    $merge: {
      into: 'phones', // collection-name
      on: 'phoneId',  // the identifier, used to identify the document to merge into
    }
  }
])

由于每个 phone # 条评论都是 >> 20,您可能希望先考虑评论 ,然后 $lookup phone秒。对于单个已知 phone 查找,以下将起作用;它将 not 对 >1 phone 起作用,因为 $limit 无法引用数据字段(即 phoneId

db.Xreviews.aggregate([
    {$match: {"phoneId":"2"}}
    ,{$sort: {"dateOfReview":-1}} // no getting around the desc sort..
    ,{$limit: 20}  // but we now limit to ONLY 20 reviews.

    // Put them "back together" as an array called "reviews"
    ,{$group: {_id:"$phoneId", reviews: {$push: "$$CURRENT"}}}

    // ... and pull in the phone data:
    ,{$lookup: {from: "Xphones", localField: "_id", foreignField: "phoneId", as: "X" }}
]);

以下将适用于 1 个或多个 phone 或全部但考虑的是评论数组在传递给 $slice 运算符以将其缩减为 20 之前可能非常大:

db.Xreviews.aggregate([
    // $match for anything or nothing here; then:
    {$sort: {"dateOfReview":-1}}

    //  The order of the _id is not deterministic BUT the docs will be
    //  pushed onto the reviews array correctly in desc order:
    ,{$group: {_id:"$phoneId", reviews: {$push: "$$CURRENT"}}}

    //  Now simply overwrite the reviews array a shortened version:
    ,{$addFields: {reviews: {$slice: ["$reviews",20] }}}

 
    ,{$lookup: {from: "Xphones", localField: "_id", foreignField: "phoneId", as: "X" }}
]);

这两个解决方案最终将 phone 详细信息存储在字段 'X' 中,这是一个包含 1 项的数组。由于我们知道 phoneID 是 1:1,如果我们想更有趣,我们可以在 $lookup 之后添加:

   // Pull item[0] out and merge with reviews AND make that the new
   // document:
   ,{$replaceRoot: { newRoot: {$mergeObjects: [ "$$CURRENT", {$arrayElemAt:["$X",0]} ]} }}
    ,{$unset: "X"}   // drop X completely

我想我结合了 Buzz 和 MarcRo 提出的两个解决方案解决了我的问题:

    db.reviews.aggregate([
{
    $sort: {
        "dateOfReview":-1
    }
},
{
    $group: {
        _id: '$phoneId',
        reviews: {
            $push: '$$CURRENT'
        }
    }
}, {
    $addFields: {
        reviews: {
            $slice: [
                '$reviews',
                20
            ]
        }
    }
}, {
    $merge: {
        into: 'phones',
        on: '_id'
    }
}])