我正在查找有关联接及其在MongoDB
中的行为的一些信息。虽然我很感激NoSQL数据库背后的很大一部分功能是将所有信息存储在文档中,并且该文档包含尽可能多的信息,这样您就不必进行多次查询
然而,我也理解,在某些情况下,您可能希望尽量减少数据重复,从而将一致性问题的风险降至最低。
使用文档引用时,是否有返回单个文档的方法?我尝试过$lookup
函数,虽然它确实返回了正确的结果,但它为每个数组条目返回一个文档。
假设以下结构:
客户:
{
_id: ObjectId("578d706916f07969c4b0cad1"),
name: "fred",
orders: [ObjectId("578d706916f07969c4b0cad2"),ObjectId("578d706916f07969c4b0cad3")]
}
订单:
{
_id: ObjectId("578d706916f07969c4b0cad2"),
date: xxxx,
items: [a,b,c,d]
},
{
_id: ObjectId("578d706916f07969c4b0cad2"),
date: xxxx,
items: [x,y,z]
}
使用查找,我可以得到2个文档的结果,每个订单都有一个文档,并附加客户数据,但我要查找的是一个带有数组或订单信息的文档——embedded document
。即以下结构
{
_id: ObjectId("578d706916f07969c4b0cad1"),
name: "fred",
orders: [
{
_id: ObjectId("578d706916f07969c4b0cad2"),
date: xxxx,
items: [a,b,c,d]
},
{
_id: ObjectId("578d706916f07969c4b0cad2"),
date: xxxx,
items: [x,y,z]
}]
}
这在MongoDB
中可能吗?还是join
流程与SQL数据库匹配得如此紧密,以至于在尝试联接数据时总是返回重复的客户信息?我知道数据可以在应用程序(如node
)中转换为单个文档,但从编写查询的方式来看,是否有可能返回预先格式化的文档?
您可以执行单个aggregation
来获得该结果。mongo$lookup
文档的一部分展示了如何使用数组进行查找。
给定以下集合:
db.user.insert({
name: "fred",
orders: [ObjectId("578d706916f07969c4b0cad2"),ObjectId("578d706916f07969c4b0cad3")]
})
db.order.insert({
_id: ObjectId("578d706916f07969c4b0cad2"),
date: ISODate("2012-12-20T06:01:17.171Z"),
items: ["a","b","c","d"]
})
db.order.insert({
_id: ObjectId("578d706916f07969c4b0cad3"),
date: ISODate("2012-12-19T06:01:17.171Z"),
items: ["x","y","z"]
})
使用:执行aggregation
orders
阵列的$unwind
_id
字段上order
集合的$lookup
$unwind
新建orders
字段,包含已查找的项目$group
乘以_id
,并将您的orders
项目重新组合在一个阵列中,不重复
聚合查询:
db.user.aggregate([{
$unwind: "$orders"
}, {
$lookup: {
from: "order",
localField: "orders",
foreignField: "_id",
as: "orders"
}
}, {
$unwind: "$orders"
}, {
$group: {
_id: "$_id",
name: {
$first: "$name"
},
orders: {
$addToSet: "$orders"
}
}
}])
这将给你:
{
"_id": ObjectId("5798a8e1968539bb0a98d1c3"),
"name": "fred",
"orders": [{
"_id": ObjectId("578d706916f07969c4b0cad3"),
"date": ISODate("2012-12-19T06:01:17.171Z"),
"items": ["x", "y", "z"]
}, {
"_id": ObjectId("578d706916f07969c4b0cad2"),
"date": ISODate("2012-12-20T06:01:17.171Z"),
"items": ["a", "b", "c", "d"]
}]
}