当我结合2个表从mongoDB集合中获取数据时,出乎我的意料。请任何人帮我解决同样的问题。
收藏集:
食谱
{
"_id":{"$oid":"5dada3c5761bb32a1201d4da"},
"CategoryName":"Biryani"
}
{
"_id":{"$oid":"5dada3c5761bb32a1201d4db"},
"CategoryName":"Mutton Biryani"
}
{
"_id":{"$oid":"5dada3c5761bb32a1201d4d4"},
"CategoryName":"Chicken Biryani"
}
{
"_id":{"$oid":"5daea43a517cf601a7e80a3b"},
"CategoryName":"Kathirikai gothsu"
}
食谱:
{
"_id":{"$oid":"5daffda85d9b4fd19ae4da30"},
"recipeTitle":"Mutton dum biryani",
"Recipetags":["Indian","NonVeg","Lunch"],
"cookTime":"30 Mins",
"recipeCategoryId":[{"$oid":"5dada3c5761bb32a1201d4da"},{"$oid":"5dada3c5761bb32a1201d4db"},{"$oid":"5dada3c5761bb32a1201d4dc"}],
"recipeCuisienId":"Indian",
"recepeType":false,
"availaleStreaming":"TEXT",
"postedOn":{"$date":{"$numberLong":"0"}},
"postedBy":"shiva@yopmail.com"
}
{
"_id":{"$oid":"5daffda85d9b4fd19ae4da30"},
"recipeTitle":"Mutton Chicken biryani",
"Recipetags":["Indian","NonVeg","Lunch"],
"cookTime":"30 Mins",
"recipeCategoryId":[{"$oid":"5dada3c5761bb32a1201d4da"},{"$oid":"5dada3c5761bb32a1201d4d4"},{"$oid":"5dada3c5761bb32a1201d4dc"}],
"recipeCuisienId":"Indian",
"recepeType":false,
"availaleStreaming":"TEXT",
"postedOn":{"$date":{"$numberLong":"0"}},
"postedBy":"shiva@yopmail.com"
}
用户:
{
"_id":{"$oid":"5da428b85e3cbd0f153c7f3b"},
"emailId":"shiva@yopmail.com",
"fullName":"siva prakash",
"accessToken":"xxxxxxxxxxxxx",
"__v":{"$numberInt":"0"}
}
节点js中的当前猫鼬代码
RecipeCatagory.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(id) } },
{
"$lookup": {
"from": "recipes",
"localField": "_id",
"foreignField": "recipeCategoryId",
"as": "recipes"
}
},
{ "$unwind": "$recipes" },
{ "$unwind": "$recipes.recipeCategoryId" },
{
"$match": {
"recipes.recipeCategoryId": mongoose.Types.ObjectId(id)
}
},
{
"$lookup": {
"from": "users",
"localField": "emailId",
"foreignField": "recipes.postedBy",
"as": "users"
}
},
])
.exec(function (err, recipes) {
if (err) {
response
.status(400)
.json({
"status": "Failed",
"message": "Error",
"data": err | err.message
});
return
} else {
response
.status(200)
.json({
"status": "Ok",
"message": "Success",
"data": recipes
});
return
}
})
使用上述查询的当前输出
{
"status": "Ok",
"message": "Success",
"data": [
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "Biryani",
"recipes": {
"_id": "5daffda85d9b4fd19ae4da30",
"recipeTitle": "Mutton dum biryani",
"Recipetags": [
"Indian",
"NonVeg",
"Lunch"
],
"cookTime": "30 Mins",
"recipeCategoryId": "5dada3c5761bb32a1201d4da",
"recipeCuisienId": "Indian",
"recepeType": false,
"availaleStreaming": "TEXT",
"postedOn": "1970-01-01T00:00:00.000Z",
"postedBy": "shiva@yopmail.com"
},
"users": [
{
"_id": "5da428b85e3cbd0f153c7f3b",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "42eb19a0-ee57-11e9-86f7-a7b758fb7271",
"__v": 0
}
]
},
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "Biryani",
"recipes": {
"_id": "5daffda85d9b4fd19ae4da31",
"recipeTitle": "Kumbakonam kathirikai gothsu",
"Recipetags": [
"Indian",
"Veg"
],
"cookTime": "30 Mins",
"recipeCategoryId": "5dada3c5761bb32a1201d4da",
"recipeCuisienId": "Indian",
"recepeType": true,
"availaleStreaming": "TEXT",
"postedOn": "1970-01-01T00:00:00.000Z",
"postedBy": "shiva@yopmail.com"
},
"users": [
{
"_id": "5da428b85e3cbd0f153c7f3b",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "xxxxxxxxxxxxx",
"__v": 0
}
]
}
]
}
**Expected Out:**
{
"status": "Ok",
"message": "Success",
"data": [
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "chiken Biryani",
"recipes": {
"_id": "5daffda85d9b4fd19ae4da30",
"recipeTitle": "Mutton dum biryani",
"Recipetags": [
"Indian",
"NonVeg",
"Lunch"
],
"cookTime": "30 Mins",
"recipeCategoryId": "5dada3c5761bb32a1201d4da",
"recipeCuisienId": "Indian",
"recepeType": false,
"availaleStreaming": "TEXT",
"postedOn": "1970-01-01T00:00:00.000Z",
"postedBy": "shiva@yopmail.com"
},
"users": [
{
"_id": "5da428b85e3cbd0f153c7f3b",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "42eb19a0-ee57-11e9-86f7-a7b758fb7271",
"__v": 0
}
]
},
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "Biryani",
"recipes": [
{
"_id": "5daffda85d9b4fd19ae4da31",
"recipeTitle": "Mutton dum biryani",
"Recipetags": [
"Indian",
"Veg"
],
"cookTime": "30 Mins",
"recipeCategoryId": "5dada3c5761bb32a1201d4da",
"recipeCuisienId": "Indian",
"recepeType": true,
"availaleStreaming": "TEXT",
"postedOn": "1970-01-01T00:00:00.000Z",
"postedBy": "shiva@yopmail.com"
},
{
"_id": "5daffda85d9b4fd19ae4da31",
"recipeTitle": "Chicken biryani",
"Recipetags": [
"Indian",
"Veg"
],
"cookTime": "30 Mins",
"recipeCategoryId": "5dada3c5761bb32a1201d4da",
"recipeCuisienId": "Indian",
"recepeType": true,
"availaleStreaming": "TEXT",
"postedOn": "1970-01-01T00:00:00.000Z",
"postedBy": "shiva@yopmail.com"
}
],
"users": [
{
"_id": "5da428b85e3cbd0f153c7f3b",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "xxxxxxxxxxxx",
"__v": 0
}
]
}
]
}
我很想得到期望的结果...我希望将食谱作为具有食谱类别的数组包含在食谱集合中...
答案 0 :(得分:2)
基本上,您这样做的方式是错误的,应该从Recipe
模型进行查询。您已经具有“类别ID值” ,它们包含在该文档的数组中。
基本上,您应该具有以下内容:
const wantedCategories = [
ObjectId("5dada3c5761bb32a1201d4da"),
ObjectId("5dada3c5761bb32a1201d4db")
];
let data = await Recipe.aggregate([
// Match wanted category(ies)
{ "$match": {
"recipeCategoryId": { "$in": wantedCategories }
}},
// Filter the content of the array
{ "$addFields": {
"recipeCategoryId": {
"$filter": {
"input": "$recipeCategoryId",
"cond": {
"$in": [ "$$this", wantedCategories ]
}
}
}
}},
// Lookup the related matching category(ies)
{ "$lookup": {
"from": RecipeCategory.collection.name,
"let": { "recipeCategoryIds": "$recipeCategoryId" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ "$_id", "$$recipeCategoryIds" ] }
}}
],
"as": "recipeCategoryId"
}},
// Lookup the related user to postedBy
{ "$lookup": {
"from": User.collection.name,
"let": { "postedBy": "$postedBy" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$emailId", "$$postedBy" ] } } }
],
"as": "postedBy"
}},
// postedBy is "singular"
{ "$unwind": "$postedBy" }
]);
哪个会返回如下结果:
{
"data": [
{
"_id": "5dbce992010163139853168c",
"Recipetags": [
"Indian",
"NonVeg",
"Lunch"
],
"recipeCategoryId": [
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "Biryani",
"__v": 0
},
{
"_id": "5dada3c5761bb32a1201d4db",
"CategoryName": "Mutton Biryani",
"__v": 0
}
],
"recipeTitle": "Mutton dum biryani",
"cookTime": "30 Mins",
"recepeType": false,
"postedBy": {
"_id": "5dbce992010163139853168e",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "xxxxxxxxxxxxx",
"__v": 0
},
"__v": 0
},
{
"_id": "5dbce992010163139853168d",
"Recipetags": [
"Indian",
"NonVeg",
"Lunch"
],
"recipeCategoryId": [
{
"_id": "5dada3c5761bb32a1201d4da",
"CategoryName": "Biryani",
"__v": 0
}
],
"recipeTitle": "Mutton Chicken biryani",
"cookTime": "30 Mins",
"recepeType": false,
"postedBy": {
"_id": "5dbce992010163139853168e",
"emailId": "shiva@yopmail.com",
"fullName": "siva prakash",
"accessToken": "xxxxxxxxxxxxx",
"__v": 0
},
"__v": 0
}
]
}
注意:实际上,我确实使用
RecipeCategory
而不是问题中显示的RecipeCatagory
来纠正模型的英文拼写。根据需要应用到自己的实现中。
您可能会注意到在不同阶段的查询表单和聚合运算符表单中,$in
与“ ID列表”的使用。就我个人而言,即使当前仅提供一个值,我也将以这种方式进行编码,因为这意味着在事件I中,除了 input 变量外,几乎没有其他更改想要多个值,例如,多面搜索选项中的“多个类别”。
尽管这仍然适用于问题中的奇异值,但这证明了“列表”自变量方法。
整个过程都遵循注释在每个管道阶段所说的,即您首先通过选定的“ category” 值将 recipes 集合中的所需“文档”进行匹配(s)。然后,我们只想删除这些文档数组中类别的所有不匹配数据。如果您只想显示与该食谱相关的所有类别(无论它们是否符合条件),则实际上可以将其视为“可选”。在这种情况下,您需要做的就是删除包含$filter
语句的阶段,这样代码就会很愉快地工作。
然后当然有$lookup
阶段,每个与相关的集合都是一个阶段。这里的示例实际上显示了$lookup
流水线阶段的表达形式。再次,这实际上仅是为了演示,因为标准localField
和foreignField
格式对于您在此处要执行的操作来说是完美的,并且不需要其他语法。无论如何,MongoDB基本上都会将较旧的语法转换为较新的表达形式,如内部所示。
您可能会注意到Model.collection.name
参数中from
的用法。当用猫鼬编码时,这实际上是一件方便的事。 MongoDB本身希望实际的集合名称作为此处的参数。由于 mongoose 通常会为所引用的实际集合提供多种名称,或者对模型定义采用显式参数,因此使用模型中的.collection.name
访问器可确保您拥有正确的名称。实际的集合名称,即使此名称在模型定义中的某些时间发生了变化。
这里唯一的其他简单步骤是最后的$unwind
,并且仅因为$lookup
的输出是始终一个数组,并且在这里替换了{匹配的内容相关的{1}}属性总是 个项目。因此,为了简化结果的可读性,我们可以将其设为单个值,而不是在此处使用数组。
对于所有内容如何组合的更多上下文,这是语句的代码和数据的创建全部包含在一个独立的列表中,当然实际上是从上面获得的“输出”获得了: / p>
postedBy