javascript - 根据某些条件,使用 mongodb 聚合从数组中获取对象以及同一级别的其他字段

标签 javascript mongodb mongodb-query aggregation-framework

我有以下数据。我想根据某些条件从 od 数组中获取对象。除此之外,我还想获得它们和名称字段。

我不太熟悉aggregate of mongodb 。所以我需要帮助来解决我的问题。

{
_id : 1,
em : '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="69080b0a29585b1a47070c1d" rel="noreferrer noopener nofollow">[email protected]</a>',
name : 'NewName',
od : 
[
    {
        "oid" : ObjectId("1234"),
        "ca" : ISODate("2016-05-05T13:20:10.718Z")
    },
    {
        "oid" : ObjectId("2345"),
        "ca" : ISODate("2016-05-11T13:20:10.718Z")
    },
    {
        "oid" : ObjectId("57766"),
        "ca" : ISODate("2016-05-13T13:20:10.718Z")
    }
]       
},
{
_id : 2,
em : '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a5c4c793c6e5dddcdf8bcbc0d1" rel="noreferrer noopener nofollow">[email protected]</a>',
name : 'NewName2',
od : 
[
    {
        "oid" : ObjectId("1234"),
        "ca" : ISODate("2016-05-11T13:20:10.718Z")
    },
    {
        "oid" : ObjectId("2345"),
        "ca" : ISODate("2016-05-12T13:20:10.718Z")
    },
    {
        "oid" : ObjectId("57766"),
        "ca" : ISODate("2016-05-05T13:20:10.718Z")
    }
]       
}

我尝试使用 $match、$project 和 $unwind 聚合来获得所需的结果。我的查询如下:-

db.collection.aggregate([
{
    $match : {
                    "od.ca" : {
                        '$gte': '10/05/2016',
                        '$lte': '15/05/2016'
                    }
                }
},
{
    $project:{
                    _id: '$_id',
                    em: 1,
                    name : 1,
                    od : 1
                }
},
{
    $unwind : "$od"
}, 
{
    $match : {
                    "od.ca" : {
                        '$gte': '10/05/2016',
                        '$lte': '15/05/2016'
                    }
                }
}])

我得到的结果是 em 和 name 以及 od 数组以及来自 od 的对象之一,即同一电子邮件 ID 有多个记录。

 {
_id : 1,
em : '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3b5a59587b0a094815555e4f" rel="noreferrer noopener nofollow">[email protected]</a>',
name : 'NewName',
od : 
[
{
    "oid" : ObjectId("57766"),
    "ca" : ISODate("2016-05-13T13:20:10.718Z")
}
]       
}
{
_id : 1,
em : '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="02636061423330712c6c6776" rel="noreferrer noopener nofollow">[email protected]</a>',
name : 'NewName',
od : 
[
{
    "oid" : ObjectId("2345"),
    "ca" : ISODate("2016-05-11T13:20:10.718Z")
}
]       
}

但是我想要的是每个电子邮件 ID 的返回结果,在 od 数组内所有与条件匹配的对象。我想要的一个输出示例是:-

 {
_id : 1,
em : '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3b5a59587b0a094815555e4f" rel="noreferrer noopener nofollow">[email protected]</a>',
name : 'NewName',
od : 
[
    {
        "oid" : ObjectId("2345"),
        "ca" : ISODate("2016-05-11T13:20:10.718Z")
    },
    {
        "oid" : ObjectId("57766"),
        "ca" : ISODate("2016-05-13T13:20:10.718Z")
    }
]       
}

我在查询中做错了什么吗?如果查询应该像这样返回,我怎样才能得到我想要的结果?有人可以告诉我应该尝试什么或者查询中的哪些更改可以帮助我获得我想要的结果吗?

最佳答案

您不一定需要一组这些聚合运算符,除非您的 MongoDB 版本早于 2.6.X 版本。 $filter 运算符(operator)会很好地完成这项工作。

考虑以下示例,其中 $filter 运算符应用于 $project 管道阶段将过滤 od 数组,仅包含 ca 日期大于或等于 '2016-05-10'< 的文档 且小于或等于 '2016-05-15':

var start = new Date('2016-05-10'),
    end = new Date('2016-05-15');

db.collection.aggregate([
    { 
        "$match": {
            "od.ca": { "$gte": start, "$lte": end }
        }
    },
    {
        "$project": {
            "em": 1,
            "name": 1,
            "od": {
                "$filter": {
                    "input": "$od",
                    "as": "o",
                    "cond": {  
                        "$and": [
                            { "$gte": [ "$$o.ca", start ] },
                            { "$lte": [ "$$o.ca", end ] }
                        ]
                    }
                }
            }
        }
    }
])

请记住,此运算符仅适用于 MongoDB 版本 3.2.X 及更高版本。


否则,对于 2.6.X3.0.X 版本,您可以结合使用 $map $setDifference 运算符来“过滤”ca 数组中的文档。

$map 运算符基本上映射由 $cond 计算的一些值。 运算符连接到一组错误值或通过给定条件的文档。 $setDifference 运算符然后返回与先前计算的集合的差值。通过前面的示例检查结果如何:

var start = new Date('2016-05-10'),
    end = new Date('2016-05-15');

db.collection.aggregate([
    { 
        "$match": {
            "od.ca": { "$gte": start, "$lte": end }
        }
    },
    {
        "$project": {
            "em": 1,
            "name": 1,
            "od": {
                "$setDifference": [
                    {
                        "$map": {
                            "input": "$od",
                            "as": "o",
                            "in": {
                                "$cond": [
                                    {  
                                        "$and": [
                                            { "$gte": [ "$$o.ca", start ] },
                                            { "$lte": [ "$$o.ca", end ] }
                                        ]
                                    },
                                    "$$o",
                                    false
                                ]
                            }
                        }
                    },
                    [false]
                ]
            }
        }
    }
])

对于 2.4.X 及更早版本,您可能必须使用 $match 的组合。 , $unwind $group 运算符以在上述运算符不存在的情况下实现相同的效果。

前面的示例演示了这一点,这就是您所尝试的,但缺少 $group 管道步骤,将所有扁平化文档分组到原始文档架构中,尽管减去过滤后的数组元素:

db.collection.aggregate([
    { 
        "$match": {
            "od.ca": { "$gte": start, "$lte": end }
        }
    },  
    { "$unwind": "$od" },
    { 
        "$match": {
            "od.ca": { "$gte": start, "$lte": end }
        }
    },
    {
        "$group": {
            "$_id": "$_id",
            "em": { "$first": "$em" },
            "name": { "$first": "$name" },
            "od": { "$push": "$od" }
        }
    }
])

关于javascript - 根据某些条件,使用 mongodb 聚合从数组中获取对象以及同一级别的其他字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37340008/

相关文章:

mongodb - 使用 MongoDB 进行嵌套分组

java - mongo Java 通过数组搜索

javascript - 语义 UI 弹出窗口 - 在初始化之前更改 HTML

javascript - 如何将值设置为 tfoot 内的元素

python - mongoengine 调用导致 django View 被调用两次

python - Mongoengine链接filter()和ReferenceField()导致 "TypeError: ' Collection'对象不可调用”

Javascript/Node.js "Function name"不是一个函数

mongodb - 大批量更新 MongoDB - forEach() 文档

javascript - 谷歌地图 API : Marker image positioning

javascript - 检查值是否在 change() 触发时改变