MongoDB [NodeJS]仅查找范围内包含数组元素的文档

时间:2016-01-20 11:42:57

标签: mongodb

我有有历史的文件。我想查找带有特殊历史记录条目的文档。 历史元素:

{
    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部分有效。如果有一个大于参考的日期,它将被输出。

1 个答案:

答案 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 运算符然后返回一个集合,其中的元素出现在第一个集合中但不出现在第二个集合中;即执行第二组相对于第一组的相对补充。在这种情况下,它将通过historydate属性返回包含与父文档无关的元素的最终event数组。