聚合匹配的项目在 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
Project with Match in aggregate not working in mongodb
提问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 $project
does 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 $match
here 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 $match
that 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 $redact
to 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 $match
and $group
later 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解释了如何在她的回答中做出更好的查询。我认为你应该尝试使用她的方法。