Mongo-Aggregate:如何与另一个集合中的字段进行比较
Mongo Aggregate: how to compare with a field from another collection?
我正在尝试实现一个从文章集合中收集未读消息的函数。收藏中的每一篇文章都有一个"讨论"条目,其中包含讨论评论子文档。这种子文档的一个例子是:
{
"id": NumberLong(7534),
"user": DBRef("users", ObjectId("...")),
"dt_create": ISODate("2015-01-26T00:10:44Z"),
"content": "The discussion comment content"
}
母文档具有以下(部分)结构:
{
model: {
id: 17676,
title: "Article title",
author: DBRef("users", ObjectId(...)),
// a bunch of other fields here
},
statistics: {
// Statistics will be stored here (pageviews, etc)
},
discussions: [
// Array of discussion subdocuments, like the one above
]
}
每个用户还有一个last_viewed
条目,它是一个文档,示例如下:
{
"17676" : "2015-01-10T00:00:00.000Z",
"18038" : "2015-01-10T00:00:00.000Z",
"18242" : "2015-01-20T00:00:00.000Z",
"18325" : "2015-01-20T00:00:00.000Z"
}
这意味着用户最后一次查看ID为17676和18038的文章的讨论评论是在2015年1月10日,而ID为18242和18325的文章的评论是在15年1月20日。
因此,我想从文章文档中收集讨论条目,对于ID为17676的文章,我想收集2015-01-10之后创建的讨论条目,而对于ID为18242的文章,我们想显示2015-01-20之后创建的论述条目。
更新
根据Neil Lunn的回复,到目前为止我创建的功能是:
function getUnreadDiscussions(userid) {
user = db.users.findOne({ 'model.id': userid });
last_viewed = [];
for(var i in user.last_viewed) {
last_viewed.push({
'id': parseInt(i),
'dt': user.last_viewed[i]
});
}
result = db.articles.aggregate([
// For now, collect just articles the user has written
{ $match: { 'model.author': DBRef('users', user._id) } },
{ $unwind: '$discussions' },
{ $project: {
'model': '$model',
'discussions': '$discussions',
'last_viewed': {
'$let': {
'vars': { 'last_viewed': last_viewed },
'in': {
'$setDifference': [
{ '$map': {
'input': '$$last_viewed',
'as': 'last_viewed',
'in': {
'$cond': [
{ '$eq': [ '$$last_viewed.id', '$model.id' ] },
'$$last_viewed.dt',
false
]
}
} },
[ false ]
]
}
}
}
}
},
// To get a scalar instead of a 1-element array:
{ $unwind: '$last_viewed' },
// Match only those that were created after last_viewed
{ $match: { 'discussions.dt_create': { $gt: '$last_viewed' } } },
{ $project: {
'model.id': 1,
'model.title': 1,
'discussions': 1,
'last_viewed': 1
} }
]);
return result.toArray();
}
整个$let
以及之后的$unwind
将数据转换为以下部分投影(注释掉最后一个$match
):
{
"_id" : ObjectId("54d9af1dca71d8054c8d0ee3"),
"model" : {
"id" : NumberLong(18325),
"title" : "Article title"
},
"discussions" : {
"id" : NumberLong(7543),
"user" : DBRef("users", ObjectId("54d9ae24ca71d8054c8b4567")),
"dt_create" : ISODate("2015-01-26T00:10:44Z"),
"content" : "Some comment here"
},
"last_viewed" : ISODate("2015-01-20T00:00:00Z")
},
{
"_id" : ObjectId("54d9af1dca71d8054c8d0ee3"),
"model" : {
"id" : NumberLong(18325),
"title" : "Article title"
},
"discussions" : {
"id" : NumberLong(7554),
"user" : DBRef("users", ObjectId("54d9ae24ca71d8054c8b4567")),
"dt_create" : ISODate("2015-01-26T02:03:22Z"),
"content" : "Another comment here"
},
"last_viewed" : ISODate("2015-01-20T00:00:00Z")
}
到目前为止,这里还不错。但现在的问题是,$match
只选择在last_viewed
日期之后创建的讨论不起作用。我得到一个空数组响应。但是,如果我硬编码日期并放入$match: { 'discussions.dt_create': { $gt: ISODate("2015-01-20 00:00:00") } }
,它就可以工作了。但我想让它从last_viewed
上取下来。
我找到了另一个SO线程,该线程已通过使用$cmp
运算符解决了此问题。
聚合的最后一部分是:
[
{ /* $match, $unwind, $project, $unwind as before */ },
{ $project: {
'model': 1,
'discussions': 1,
'last_viewed': 1,
'compare': {
$cmp: [ '$discussions.dt_create', '$last_viewed' ]
}
} },
{ $match: { 'compare': { $gt: 0 } } }
]
聚合框架很棒,但它在解决问题时采用了完全不同的方法。希望这能帮助到任何人!
我会不回答这个问题,以防其他人有更好的答案/方法。如果这个答案已经被投票支持了足够多次,我会接受这个。
- MongoDB-通过比较集合和对象的数组来返回现有字段的数组
- 比较两个输入字段
- javascript计算字段比较算法
- 用于比较日期字段的Javascript
- jQuery-字段值和比较
- Mongo-Aggregate:如何与另一个集合中的字段进行比较
- 比较 angularjs 指令中的两个字段
- Javascript 密码字段比较
- 使用 JavaScript 比较 2 个数组并创建一个新的对象数组,该数组不包含与 id 字段匹配的对象
- 比较两个字段的验证
- MongoDB:将Days字段添加到DB中的Date Type字段中,然后与当前日期进行比较
- 现有字段的比较
- 尝试访问动态生成的输入字段,并将其与长度一致的.json数据进行比较
- 如何将字段数据与其他字段数据进行比较
- 比较并验证输入字段
- jquery验证器比较2个字段的错误
- 创建对象和比较字段时出现Javascript错误
- 将组合框中的值与隐藏字段中的值进行比较
- 如何使用jQuery验证器比较两个字段
- jQuery比较数组输入字段