我在 Mongo DB 中有一个集合,看起来像这样 -
const clientsColection = {
"_id" : ObjectId("5ec8492c27ecdc17362b86cb"),
"clientName" : "data" ,
"users" : [
{
"roles" : [],
"operations" : [],
"_id" : ObjectId("5ecac60ab527bd0ba4a615cf"),
"isAdmin" : false,
"username" : "Adduser"
},
{
"roles" : [],
"operations" : [],
"_id" : ObjectId("5ecac60ab527bd0ba4a616cf"),
"isAdmin" : false,
"username" : "new"
}
],
"kpiObj" : [
{
"kpiName" : "epsilon",
"resultObj" : {
"result" : [
{
"mark" : 4,
"plz" : "01069"
},
{
"mark" : 5,
"plz" : "01067"
}
],
}
},
{
"kpiName" : "epsilon2",
"resultObj" : {
"result" : [
{
"mark" : 3,
"plz" : "01069"
},
{
"mark" : 1,
"plz" : "01067"
}
],
}
}
]
}
我正在尝试使用 aggregate
、project
、filter
运算符对嵌套的对象数组执行筛选,但我没有成功尚未获得预期的输出。
我想实现以下目标:-
- 阶段 1:为
users.username
匹配users
数组对象并检索匹配的对象数组(始终只有 1 个)。 - 阶段 2:将阶段 1 的输出与
kpiObj
中的kpiName
匹配,并检索匹配的对象数组(始终只有一个)。 - 第 3 阶段。将第 2 阶段的输出与
resultObj
中的mark
匹配,并检索匹配的对象数组。
在过去的 3 天里,我看了几个教程并经历了几个堆栈溢出问题,但未能获得预期的输出。 通过使用以下查询,我已经能够获得 stage1 的预期输出。任何帮助将不胜感激。
db.getCollection("clientsCollection").aggregate([
{ $match: { 'users.username': 'Adduser' } },
{
$project: {
users: {
$filter: {
input: '$users',
as: 'user',
cond: { $eq: ['$$user.username', 'Adduser'] }
}
}, 'kpiObj.kpiName':1, 'kpiObj.resultObj.result.score':1 , 'kpiObj.resultObj.result.plz':1
}
}
])
输出*
用于将 username
匹配为 Adduser
,将 kpiObj.kpiName
匹配为 epsilon
和 kpiObj.resultObj。 result.mark
为 4,我期待以下输出:-
const clientsColection = {
"_id" : ObjectId("5ec8492c27ecdc17362b86cb"),
"clientName" : "data" ,
"users" : [
{
"username" : "Adduser"
}
],
"kpiObj" : [
{
"kpiName" : "epsilon",
"resultObj" : {
"result" : [
{
"mark" : 4,
"plz" : "01069"
}
],
}
}
]
}
最佳答案
尝试下面的聚合查询:
db.collection.aggregate([
/** Filter for docs with possible conditions */
{
$match: {
"users.username": "Adduser",
"kpiObj.kpiName": "epsilon",
"kpiObj.resultObj.result.mark": 4
}
},
/** Re-create `users` array with new users array with only matching object */
{
$addFields: { users: { $filter: { input: "$users", cond: { $eq: [ "$$this.username", "Adduser" ] } } } }
},
/** Re-create `kpiObj` array with new kpiObj array with only matching object */
{
$addFields: {
kpiObj: {
$filter: { input: "$kpiObj", cond: { $eq: [ "$$this.kpiName", "epsilon" ] } }
}
}
},
/** Unwind (Split array into objects - here you'll have only 1) for flexibility to iterate over `kpiObj.resultObj.result` */
{
$unwind: "$kpiObj"
},
/** Re-create `kpiObj.resultObj.result` array with new result array with only matching object */
{
$addFields: {
"kpiObj.resultObj.result": {
$filter: { input: "$kpiObj.resultObj.result", cond: { $eq: [ "$$this.mark", 4 ] } }
}
}
},
/** remove docs where there is not match on `kpiObj.resultObj.result` */
{
$match: { "kpiObj.resultObj.result": { $ne: [] } }
},
/** I would consider `kpiObj` & `users` as single objects `{}`,
* ratherthan array of single objects `[{}]`
* Just in case if you need to be an array making object to array
* */
{
$addFields: { kpiObj: [ "$kpiObj" ] }
}
])
测试: mongoplayground
注意:
您可以使用$project
代替$addFields
来限制每个阶段的字段。如您所愿,最后添加此阶段:
{
$project: {
"users.username": 1,
kpiObj: 1
}
}
或在 users
数组上迭代时将 $filter
替换为 $map
并且只返回必填字段而不是整个对象。
关于mongodb - 在 Mongodb 中过滤深度嵌套的对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62205453/