聚合匹配的项目在 mongodb 中不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33752817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:34:52  来源:igfitidea点击:

Project with Match in aggregate not working in mongodb

mongodbmongodb-queryaggregation-framework

提问by Ubiquitous Developers

I am trying to fetch data based on some match condition. First I've tried this: Here ending_date is full date format

我正在尝试根据某些匹配条件获取数据。首先我试过这个:这里的ending_date是完整的日期格式

    Offer.aggregate([ 
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3
        }
    },
    {
        $group : {
            _id : { year: { $year : "$ending_date" }, month: { $month : "$ending_date" }}, 
            count : { $sum : 1 }
        }
    }], 
    function (err, res)
    { if (err) ; // TODO handle error 
         console.log(res); 
    });

which gives me following output:

这给了我以下输出:

[ { _id: { year: 2015, month: 11 }, count: 2 } ]

Now I want to check year also, so I am trying this:

现在我也想检查年份,所以我正在尝试这个:

    Offer.aggregate([
    {
        $project: {
            myyear: {$year: "$ending_date"}
        }
    },
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3,
            $myyear : "2015"
        }
    },
    {
        $group : {
            _id : { year: { $year : "$ending_date" }, month: { $month : "$ending_date" }}, 
            count : { $sum : 1 }
        }
    }], 
    function (err, res)
    { if (err) ; // TODO handle error 
         console.log(res); 
    });

which gives me following output:

这给了我以下输出:

 []

as you can see, _id has 2015 as a year, so when I match year it should be come in array. But I am getting null array. Why this?

如您所见,_id 以 2015 年为年份,因此当我匹配年份时,它应该排在数组中。但我得到空数组。为什么这个?

Is there any other way to match only year form whole datetime?

有没有其他方法可以只匹配年份形式的整个日期时间?

Here is the sample data

这是示例数据

{
    "_id": {
        "$oid": "56348e7938b1ab3c382d3363"
    },
    "carer_id": "55e6f647f081105c299bb45d",
    "user_id": "55f000a2878075c416ff9879",
    "starting_date": {
        "$date": "2015-10-15T05:41:00.000Z"
    },
    "ending_date": {
        "$date": "2015-11-19T10:03:00.000Z"
    },
    "amount": "850",
    "total_days": "25",
    "status": 3,
    "is_confirm": false,
    "__v": 0
}
{
    "_id": {
        "$oid": "563b5747d6e0a50300a1059a"
    },
    "carer_id": "55e6f647f081105c299bb45d",
    "user_id": "55f000a2878075c416ff9879",
    "starting_date": {
        "$date": "2015-11-06T04:40:00.000Z"
    },
    "ending_date": {
        "$date": "2015-11-16T04:40:00.000Z"
    },
    "amount": "25",
    "total_days": "10",
    "status": 3,
    "is_confirm": false,
    "__v": 0
}

回答by Blakes Seven

You are doing so many things wrong here, that it really warrants an explanation so hopefully you learn something.

你在这里做错了很多事情,它确实值得解释,所以希望你能学到一些东西。

Its a Pipeline

它是一个管道



It's the most basic concept but the one people do not pick up on the most often ( and even after continued use ) that the aggregation "pipeline" is just exactly that, being "piped" processes that feed input into the each stage as it goes along. Think "unix pipe" |:

这是最基本的概念,但人们最常(甚至在继续使用之后)并没有意识到聚合“管道”就是这样,“管道”过程将输入输入到每个阶段沿着。想想“unix 管道” |

ps -ef | grep mongo | tee out.txt

You've seen something similar before no doubt, and it's the basic concept that output from the first thing goes to the next thing and then that manipulates to give input to the next thing and so on.

毫无疑问,你以前见过类似的东西,它的基本概念是从第一件事输出到下一件事,然后操纵以向下一件事提供输入等等。

So heres the basic problem with what you are asking:

所以继承人你问的基本问题:

    {
        $project: {
            myyear: {$year: "$ending_date"}
        }
    },
    { 
        $match: { 
            carer_id : req.params.carer_id,
            status : 3,
            $myyear : "2015"
        }
    },

Consider what $projectdoes here. You specify fields you want in the output and it "spits them out", and possibly with manipulation. Does it output these fields in "addition" the the fields in the document? No It does not. Only what you ask to come out actually comes out and can be used in the following pipeline stage(s).

考虑一下$project这里做了什么。您在输出中指定所需的字段,它会“将它们吐出”,并可能进行操作。它是否在“添加”文档中的字段中输出这些字段?不,它没有。只有你要求出来的东西才会真正出来,并且可以在接下来的管道阶段中使用。

The $matchhere essentially asks for fields that are no longer present, because you only asked for one thing in the output. The same problem occurs further down as again you ask for fields you removed earlier and there simply is nothing to reference, but also everything was already removed by a $matchthat could not match anything.

$match这里主要询问的是不再存在领域,因为你只要求输出的一件事。同样的问题发生在更远的地方,因为您再次要求您之前删除的字段,并且根本没有任何可参考的内容,而且所有内容都已被$match无法匹配的内容删除。

Also, that is not how field projections work as you have entered

此外,这不是您输入的字段投影的工作方式

So just use a range for the date

所以只需使用日期范围



        { "$match": { 
            "carer_id" : req.params.carer_id,
            "status" : 3,
            "ending_date": { 
                "$gte": new Date("2015-01-01"), 
                "$lt": new Date("2016-01-01")
            }
        }},
        { "$group": {
            "_id": { 
                "year": { "$year": "$ending_date" }, 
                "month": { "$month": "$ending_date" }
            }, 
            "count": { "$sum": 1 }
        }}

Why? Because it just makes sense. If you want to match the "year" then supply the date range for the whole year. We could play silliness with $redactto match on the extracted year value, but that is just wasted processing time.

为什么?因为它只是有道理。如果要匹配“年份”,请提供全年的日期范围。我们可以愚蠢$redact地匹配提取的年份值,但这只是浪费了处理时间。

Doing this way is the fastest to process and can actually use an index to process faster. So don't otherthink the problem and just ask for the date range you want.

这样做处理速度最快,实际上可以使用索引来更快地处理。所以不要想着这个问题,只需询问你想要的日期范围。

回答by Dmytro Shevchenko

You forgot to project the fields that you're using in $matchand $grouplater on. For a quick fix, use this query instead:

您忘记投影您正在使用的字段$match以及$group稍后的内容。要快速修复,请改用此查询:

Offer.aggregate([
{
    $project: {
        myyear: { $year: "$ending_date" },
        carer_id: 1,
        status: 1,
        ending_date: 1
    }
},
{ 
    $match: { 
        carer_id: req.params.carer_id,
        myyear: 2015,
        status: 3
    }
},
{
    $group: {
        _id: {
            year: { $year: "$ending_date" },
            month: { $month: "$ending_date" }
        }, 
        count: { $sum: 1 }
    }
}], 
function (err, res)
{
    if (err) {} // TODO handle error 
    console.log(res); 
});

That said, Blakes Sevenexplained how to make a better query in her answer. I think you should try and use her approach instead.

也就是说,Blakes Seven解释了如何在她的回答中做出更好的查询。我认为你应该尝试使用她的方法。