我有有历史的文件。我想查找带有特殊历史记录条目的文档。 历史元素:
{
name:"added",
date: Isodate
}
查询应该获取名称为“已添加”且日期低于引用的所有文档。如果日期更高,则应跳过该文档。文档可以有多个“添加”事件
这是我的查询,查找所有添加了7天范围内历史元素的文档,如果一个元素低于7天,则不应显示该文档:
var expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() - 7);
var query = {
$and: [
{
history: {
$elemMatch:{
event: "added",
date: {
$not: {
$gte: expiryDate.toISOString()
},
}
}
}
},
{
history: {
$elemMatch: {
event: "added",
date: {
$lt: expiryDate.toISOString()
}
}
}
}
]
}
这是电话:
self.db.items.find(query).toArray(function (err, items) {
if(items)
console.log(items.length);
});
问题是,只有$ lte部分有效。如果有一个大于参考的日期,它将被输出。
答案 0 :(得分:1)
考虑一种替代方案,例如 aggregation framework 。运行以下管道将为您提供所需的结果,并根据给定的日期条件筛选history
数组。
注意:没有契约将JavaScript Date对象强制转换为ISOString,因为Mongo使用ISODate帮助程序包装了 Date
类型的对象,但在内部原生JS Date对象存储为64位整数,表示自Unix纪元(1970年1月1日)以来的毫秒数,这导致过去和未来的可表示日期范围约为2.9亿年。
var expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() - 7);
var pipeline = [
{
"$match": {
"history.event": "added",
"history.date": { "$lt": expiryDate }
}
},
{
"$project": {
"other_fields": 1,
"history": {
"$setDifference": [
{
"$map": {
"input": "$history",
"as": "el",
"in": {
"$cond": [
{
"$and": [
{ "$eq": [ "$$el.event", "added" ]}
{ "$lt": [ "$$el.date", expiryDate ]}
]
},
"$$el",
false
]
}
}
},
[false]
]
}
}
}
];
db.collection.aggregate(pipeline)
上述管道涉及过滤history
数组,以便删除不符合上述条件的文档。这可以通过 $setDifference
和 $map
运算符实现。
$map
运算符本质上创建了一个新的数组字段,该字段在子表达式中对数组的每个元素进行评估逻辑时保存值。 $setDifference
运算符然后返回一个集合,其中的元素出现在第一个集合中但不出现在第二个集合中;即执行第二组相对于第一组的相对补充。在这种情况下,它将通过history
和date
属性返回包含与父文档无关的元素的最终event
数组。