Mongodb 如何使$lookup直接嵌入文档而不是将其包装到数组中?
我有这样一份文件:Mongodb 如何使$lookup直接嵌入文档而不是将其包装到数组中?,mongodb,Mongodb,我有这样一份文件: { "_id": ObjectId("5d779541bd4e75c58d598212") "client": ObjectId("5d779558bd4e75c58d598213") } { from: 'client', localField: 'client', foreignField: 'id', as: 'client', } 当我这样做$lookup时: { "_id": ObjectId("5d779
{
"_id": ObjectId("5d779541bd4e75c58d598212")
"client": ObjectId("5d779558bd4e75c58d598213")
}
{
from: 'client',
localField: 'client',
foreignField: 'id',
as: 'client',
}
当我这样做$lookup
时:
{
"_id": ObjectId("5d779541bd4e75c58d598212")
"client": ObjectId("5d779558bd4e75c58d598213")
}
{
from: 'client',
localField: 'client',
foreignField: 'id',
as: 'client',
}
我得到:
{
"_id": ObjectId("5d779541bd4e75c58d598212")
"client":[
{
... client info wrapped in array
}
]
}
这迫使我在查找阶段之后添加$unwind
在本例中,这很好,因为我知道它是一个正则字段(不是数组)。但在其他集合中,我有ObjectId的数组
,我不想解开它们
我应该如何告诉mongo
仅当它不是数组时才展开?添加带有
查找总是返回一个数组,因为它不知道是一对一映射还是一对多映射。但是,我们可以确保查找返回单个文档,并且该文档将包含在常规查找中作为数组出现的所有文档
方法如下:
db.collection.aggregate([
{
$lookup:{
"from":"client",
"let":{
"client":"$client"
},
"pipeline":[
{
$match:{
$expr:{
$eq:["$id","$$client"]
}
}
},
{
$group:{
"_id":null,
"data":{
$push:"$$ROOT"
}
}
},
{
$project:{
"_id":0
}
}
],
"as":"clientLookup"
}
},
{
$unwind:"$clientLookup"
}
]).pretty()
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820c"),
"client" : 1,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d59820e"),
"id" : 1,
"name" : "Tony"
},
{
"_id" : ObjectId("5d779322bd4e75c58d59820f"),
"id" : 1,
"name" : "Thor"
},
{
"_id" : ObjectId("5d779322bd4e75c58d598210"),
"id" : 1,
"name" : "Natasha"
}
]
}
}
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820d"),
"client" : 2,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d598211"),
"id" : 2,
"name" : "Banner"
}
]
}
}
查询分析:我们正在查找客户机
集合,并在其中执行管道。该管道的输出将保存data
字段中的每个匹配文档
数据集:
收藏:收藏
{
"client":1
}
{
"client":2
}
收集:客户端
{
"id":1,
"name":"Tony"
}
{
"id":1,
"name":"Thor"
}
{
"id":1,
"name":"Natasha"
}
{
"id":2,
"name":"Banner"
}
输出:
db.collection.aggregate([
{
$lookup:{
"from":"client",
"let":{
"client":"$client"
},
"pipeline":[
{
$match:{
$expr:{
$eq:["$id","$$client"]
}
}
},
{
$group:{
"_id":null,
"data":{
$push:"$$ROOT"
}
}
},
{
$project:{
"_id":0
}
}
],
"as":"clientLookup"
}
},
{
$unwind:"$clientLookup"
}
]).pretty()
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820c"),
"client" : 1,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d59820e"),
"id" : 1,
"name" : "Tony"
},
{
"_id" : ObjectId("5d779322bd4e75c58d59820f"),
"id" : 1,
"name" : "Thor"
},
{
"_id" : ObjectId("5d779322bd4e75c58d598210"),
"id" : 1,
"name" : "Natasha"
}
]
}
}
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820d"),
"client" : 2,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d598211"),
"id" : 2,
"name" : "Banner"
}
]
}
}
为什么要返回带有数组或对象的字段。我希望Mongo保持数据的“形状”:当我有{client:ObjectId(“…”)时,当找不到客户机时,我希望收到null
,或者直接收到{client:{all the client fields}
,但如果我的原始字段是{clients:[ObjectId(…),ObjectId(…])
然后我希望它返回{clients:[{…},{…}]}
基本上我想要与mongoose.populate相同的行为,但是在mongo服务器端不知道为什么要这样做,但是可以这样做db.collection.aggregate([{$project:{$collection:{$cond:[{$eq:[{$size:$collection”},1]},{$arrayElemAt:[“$collection”,0]},“$collection”]}]
@Ashh可能有用,但如果原始(“待填充”字段)最初是一个数组(恰好长度为1),它仍然会导致问题因为现在如果我们尝试填充它并使用该代码段,它会将其转换为常规对象基本上我希望mongo这样做:如果原始非数组,则将其保留为非数组。如果它是数组,则返回为数组。不幸的是,这是不可能的,因为$lookup
不返回而不是数组。这仍然是相同的问题。我有要知道我“填充”的字段最初是常规字段还是数组。因为如果我对数组使用相同的查询,它将只返回第一个“填充”项。只有一个问题您的架构类型是clientId:ObjectId()还是clientId:[ObjectId(),ObjectId(),,,,,,,]?