请考虑以下事项。 我有文件,我保存字段的版本。 原始文档中的字段可以为null,我只保存实际更改的字段。 例如:
{
_id : abc,
state : 'NEW',
field2 : 'WILL NOT CHANGE',
field3 : null,
lastChange : 1236547
changes : [
{
state : 'WORKING',
field3 : 'SOMETHING'
},
{
state : 'DONE'
}
]
}
在我的聚合管道中,我通过将所有版本与文档根合并来构建最新版本的文档。这意味着我避免了复杂的查询,我在其中搜索更改数组并找到我想要查找的每个字段的最新版本,并且我受益于管道将最新文档版本作为文档返回的副作用。下面的管道在我的问题所在的位置结束。在应用程序中,还有更多的阶段进行计数和分组等。
Mongoose: meldungs.aggregate([
{
'$match': {
'$and': [{
lastChange: {
'$ne': null
}
},
{
lastChange: {
'$gte': ISODate('2017-03-01T23:00:00.000Z')
}
},
{
lastChange: {
'$lt': ISODate('2017-03-02T22:59:59.999Z')
}
}]
}
},
{
'$replaceRoot': {
newRoot: {
'$arrayToObject': {
'$reduce': {
input: '$changes',
initialValue: {
'$filter': {
input: {
'$objectToArray': '$$ROOT'
},
as: 'field',
cond: {
'$and': [
{ $ne : [ '$$field.v', null ] },
{ $ne : [ '$$field.k', '_id' ] }
]
}
}
},
in: {
'$concatArrays': ['$$value',
{
'$filter': {
input: {
'$objectToArray': '$$this.changes'
},
as: 'field',
cond: {
$ne : [ '$$field.v', null ]
}
}
}]
}
}
}
}
}
},
{
'$match': {
state: { '$eq': 'DONE' }
}
],
{})
这很有效,新文档看起来很正常:
{
state : 'DONE',
field2 : 'WILL NOT CHANGE',
field3 : 'SOMETHING',
lastChange : 1236547
}
我的问题是,合并/缩小之后的匹配阶段无法查询'新文件。相反,似乎使用了旧的字段值。
state: { '$eq': 'DONE' } // should return the document, but doesn't
state: { '$eq': 'NEW' } // should NOT return the document but does
我最好的猜测是,这与管道优化有关吗?意味着优化器将$ match语句移动到第一阶段,或类似的东西。 有没有人也有这个问题并且知道解决方案?
经过更多测试后,似乎使用$$ ROOT作为reduce的initialValue是问题的一部分。如果我使用一个空数组作为initialValue,我可以正确匹配减少的字段。