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'
}
}])
我有以下 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'
}
}])