本质上,我正在尝试过滤掉被"丢弃"的子文档和子文档。这是我的架构的精简版本:
permitSchema = {
_id,
name,
...
feeClassifications: [
new Schema({
_id,
_trashed,
name,
fees: [
new Schema({
_id,
_trashed,
name,
amount
})
]
})
],
...
}
所以我能够得到我想要的效果 feeClassifications
.但我正在努力寻找一种方法来对feeClassifications.fees
产生同样的效果。
因此,这可以根据需要工作:
Permit.aggregate([
{ $match: { _id: mongoose.Types.ObjectId(req.params.id) }},
{ $project: {
_id: 1,
_name: 1,
feeClassifications: {
$filter: {
input: '$feeClassifications',
as: 'item',
cond: { $not: {$gt: ['$$item._trashed', null] } }
}
}
}}
])
但是我也想过滤嵌套数组fees
.我尝试了一些方法,包括:
Permit.aggregate([
{ $match: { _id: mongoose.Types.ObjectId(req.params.id) }},
{ $project: {
_id: 1,
_name: 1,
feeClassifications: {
$filter: {
input: '$feeClassifications',
as: 'item',
cond: { $not: {$gt: ['$$item._trashed', null] } }
},
fees: {
$filter: {
input: '$fees',
as: 'fee',
cond: { $not: {$gt: ['$$fee._trashed', null] } }
}
}
}
}}
])
这似乎最接近君主文档。但是我得到错误: this object is already an operator expression, and can't be used as a document expression (at 'fees')
更新:-----------
根据要求,下面是一个示例文档:
{
"_id" : ObjectId("57803fcd982971e403e3e879"),
"_updated" : ISODate("2016-07-11T19:24:27.204Z"),
"_created" : ISODate("2016-07-09T00:05:33.274Z"),
"name" : "Single Event",
"feeClassifications" : [
{
"_updated" : ISODate("2016-07-11T19:05:52.418Z"),
"_created" : ISODate("2016-07-11T17:49:12.247Z"),
"name" : "Event Type 1",
"_id" : ObjectId("5783dc18e09be99840fad29f"),
"fees" : [
{
"_updated" : ISODate("2016-07-11T18:51:10.259Z"),
"_created" : ISODate("2016-07-11T18:41:16.110Z"),
"name" : "Basic Fee",
"amount" : 156.5,
"_id" : ObjectId("5783e84cc46a883349bb2339")
},
{
"_updated" : ISODate("2016-07-11T19:05:52.419Z"),
"_created" : ISODate("2016-07-11T19:05:47.340Z"),
"name" : "Secondary Fee",
"amount" : 50,
"_id" : ObjectId("5783ee0bad7bf8774f6f9b5f"),
"_trashed" : ISODate("2016-07-11T19:05:52.410Z")
}
]
},
{
"_updated" : ISODate("2016-07-11T18:22:21.567Z"),
"_created" : ISODate("2016-07-11T18:22:21.567Z"),
"name" : "Event Type 2",
"_id" : ObjectId("5783e3dd540078de45bbbfaf"),
"_trashed" : ISODate("2016-07-11T19:24:27.203Z")
}
]
}
这是所需的输出("垃圾"子文档被排除在feeClassifications
和fees
{
"_id" : ObjectId("57803fcd982971e403e3e879"),
"_updated" : ISODate("2016-07-11T19:24:27.204Z"),
"_created" : ISODate("2016-07-09T00:05:33.274Z"),
"name" : "Single Event",
"feeClassifications" : [
{
"_updated" : ISODate("2016-07-11T19:05:52.418Z"),
"_created" : ISODate("2016-07-11T17:49:12.247Z"),
"name" : "Event Type 1",
"_id" : ObjectId("5783dc18e09be99840fad29f"),
"fees" : [
{
"_updated" : ISODate("2016-07-11T18:51:10.259Z"),
"_created" : ISODate("2016-07-11T18:41:16.110Z"),
"name" : "Basic Fee",
"amount" : 156.5,
"_id" : ObjectId("5783e84cc46a883349bb2339")
}
]
}
]
}
由于我们要过滤外部和内部数组字段,因此可以使用 $map
变量运算符,该运算符返回具有我们想要的"值"的数组。
在$map
表达式中,我们提供了一个逻辑$cond
itional $filter
,用于从文档和子文档数组字段中删除不匹配的文档。
条件$lt
当子文档和/或子文档数组字段中没有字段"_trashed"时返回 true。
请注意,在$cond
表达式中,我们还为<false case>
返回 false。当然,我们需要对$map
结果应用过滤器以删除所有false
。
Permit.aggregate(
[
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{ "$project": {
"_updated": 1,
"_created": 1,
"name": 1,
"feeClassifications": {
"$filter": {
"input": {
"$map": {
"input": "$feeClassifications",
"as": "fclass",
"in": {
"$cond": [
{ "$lt": [ "$$fclass._trashed", 0 ] },
{
"_updated": "$$fclass._updated",
"_created": "$$fclass._created",
"name": "$$fclass.name",
"_id": "$$fclass._id",
"fees": {
"$filter": {
"input": "$$fclass.fees",
"as": "fees",
"cond": { "$lt": [ "$$fees._trashed", 0 ] }
}
}
},
false
]
}
}
},
"as": "cls",
"cond": "$$cls"
}
}
}}
]
)
在即将发布的MongoDB版本中(截至撰写本文时和MongoDB 3.3.5以来),您可以将$map
表达式中的$cond
表达式替换为$switch
表达式:
Permit.aggregate(
[
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{ "$project": {
"_updated": 1,
"_created": 1,
"name": 1,
"feeClassifications": {
"$filter": {
"input": {
"$map": {
"input": "$feeClassifications",
"as": "fclass",
"in": {
"$switch": {
"branches": [
{
"case": { "$lt": [ "$$fclass._trashed", 0 ] },
"then": {
"_updated": "$$fclass._updated",
"_created": "$$fclass._created",
"name": "$$fclass.name",
"_id": "$$fclass._id",
"fees": {
"$filter": {
"input": "$$fclass.fees",
"as": "fees",
"cond": { "$lt": [ "$$fees._trashed", 0 ] }
}
}
}
}
],
"default": false
}
}
}
},
"as": "cls",
"cond": "$$cls"
}
}
}}
]
)
对于更复杂的 bigdats,这将是不必要的困难。只需通过添加虚线注释字段$filter输入中对其进行编辑即可。您可以通过虚线注释将文档搜索到任何深度的 JSON,而无需进一步复杂的$filter映射。
"$filter":{
"input": "$feeClassifications._trashed",
"as": "trashed",
"cond": { "$lt": [ "$$trashed._trashed", 0 ] }
}