MongoDB一对多查询



我在MongoDB中遇到反向查找问题,并且没有单词来表达我想在Google搜索中做的事情。

例如,我有一个Client集合。Order集合具有对Client的引用和一个对Salesman的引用。

有没有办法:

  • 获取包含其orders数组的所有clients的列表(假设我们不在client中存储引用数组?
  • 获取所有与乔治salesman打过交道clients的名单?

数据看起来像

客户:

[
{_id: ObjectId('c1'), name:'blow', fname: 'joe'},
{_id: ObjectId('c2'), name:'smith', fname: 'john'},
]

订单:

[
{_id: ObjectId('o1'), item: 'wrench', client: ObjectId('c1'), salesman: ObjectId('s1')},
{_id: ObjectId('o2'), item: 'monkey wrench', client: ObjectId('c1'), salesman: ObjectId('s1')},
{_id: ObjectId('o2'), item: 'spanner', client: ObjectId('c1'), salesman: ObjectId('s2')}
]

推销员:

[
{_id: ObjectId('s1'), name:'smith', fname: 'terry'},
{_id: ObjectId('s2'), name:'wick', fname: 'john'},
]

在我列出clients的查询中,我希望看到:

[
{_id: ObjectId('c1'), name:'blow', fname: 'joe', orders: [ObjectId('o1'), ObjectId('o2'), ObjectId('o3')]},
{_id: ObjectId('c2'), name:'smith', fname: 'john', orders: []}
]

在我希望看到的销售人员名单中:

[
{_id: ObjectId('s1'), name:'smith', fname: 'terry', clients: [ObjectId('c1')]},
{_id: ObjectId('s2'), name:'wick', fname: 'john', clients: [ObjectId('c1')]}
]

我已经看到了MongoDB的建议,在一对多关系中,我不应该在client中保留可变的orders数组,在salesman中保留orders/clients,但我不知道如何执行那种"加入"我来自SQL背景。

在一个结构中,order指的是clientsalesman,反之亦然,我如何得到它?

也许有点晚了,但你可以像这样实现你的关系:

客户端查询:
  • 加入收藏的第一$lookup
  • 然后$project输出您想要的值。在这种情况下,使用$map仅从每个_id键中获取值进入"订单"。
db.clients.aggregate([
{
"$lookup": {
"from": "orders",
"localField": "_id",
"foreignField": "client",
"as": "orders"
}
},
{
"$project": {
"_id": 1,
"fname": 1,
"name": 1,
"orders": {
"$map": {
"input": "$orders",
"in": "$$this._id"
}
}
}
}
])

这里的例子

业务员查询:

同样的想法,使用第一个$lookup进行连接,$map来获取_ids。同样在这里,您可以使用$setInteresection来避免重复值。

db.salesmen.aggregate([
{
"$lookup": {
"from": "orders",
"localField": "_id",
"foreignField": "salesman",
"as": "clients"
}
},
{
"$addFields": {
"clients": {
"$setIntersection": {
"$map": {
"input": "$clients",
"in": "$$this.client"
}
}
}
}
}
])

这里的例子

其他查询

而且,要回答问题

获取所有与乔治salesman打过交道clients的名单?

您可以使用两个$lookup和两个$unwind,如下所示:

  • 首先$match只得到关于"推销员乔治"的查询。
  • 然后加入"订单"收集。
  • $unwind获取字段orders.client并使用文档collection再次加入($lookup)。
  • $unwind一次又一次,$group没有_id让所有客户端都存在。
db.salesmen.aggregate([
{
"$match": {
"name": "George"
}
},
{
"$lookup": {
"from": "orders",
"localField": "_id",
"foreignField": "salesman",
"as": "orders"
}
},
{
"$unwind": "$orders"
},
{
"$lookup": {
"from": "clients",
"localField": "orders.client",
"foreignField": "_id",
"as": "clients"
}
},
{
"$unwind": "$clients"
},
{
"$group": {
"_id": null,
"clients": {
"$addToSet": "$clients"
}
}
}
])

这里的例子

最新更新