这是我的猫鼬系列中的一个文件:
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar',
values:
[
{ y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a204 },
{ y: 0,
x: Wed Aug 26 2015 11:12:57 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a203 },
{ y: 1,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit);
_id: 55ae7be91fa1511c1795c5ae }
]
}
所以,我需要查找具有特定值的所有文档。之后,我需要返回包含所有字段并找到值元素的文档。
Wenn我试试
.find({'values.x': mTime1})
.select({
'_id' : 1 ,
'id' : 1 ,
'kind' : 1 ,
'isBoolean' : 1 ,
'values' : {$elemMatch: {x: time1}}
})
我只收到第一个找到的值:
{ ...
values:
[ { exceeds: null,
y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7d86870b92b8056bed4c } ]
}
下一个版本
.aggregate({"$unwind" : "$values"}, {"$match" : {"values.x": time1}},
{"$group" : {
'_id' : '$_id',
'values' : {$addToSet: "$values"}
});
返回除其他字段以外的所有匹配值...
我的目标是:
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar',
values:
[
{ y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a204 },
{ y: 1,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit);
_id: 55ae7be91fa1511c1795c5ae }
]
}
你有什么想法,如何用猫鼬实现这一目标? :)
更新: 感谢tsturzl,我使用下一个函数解决了它(不更改模型):
self.aggregate(
{'$unwind' : '$values'},
{'$match' : { 'values.x': mTime1} },
{'$group' : {
'_id' : '$_id',
'values' : {$push: '$values'}
}}
)
.exec(
function(err, results) {
if(err) return done(err);
var values = {}; // hashMap to group values
results.forEach(function(item) {
if(item.values) // prevent empty results
values[item._id] = item.values;
});
self.find({_id:{$in: _.keys(values)}})
.exec(function(err, items) {
if(err) return done(err);
var results = items.map(function(item) {
item.values = values[item._id];
return item;
});
done(err, results); // callback results
});
});
答案 0 :(得分:1)
在投影中使用elemMatch的问题是它访问单个项目。与数组arr[1]
类似,elemMatch获取数组中项的索引,然后将该数组项投射到该索引处。因此,您只能使用此方法检索一个子文档。
您可以使用类似于此
的聚合[
{$match: {'values.x': mTime1}}, //match before to reduce size of unwound
{$unwind: '$values'},
{$match: {'values.x': mTime1}},
{$group: {
_id: '$_id',
id: {$first: '$id'},
kind: {$first: '$kind'},
isBoolean: {$first: '$isBoolean'},
values: {$push: '$values'}
}
]
我已经测试过这个在子文档数组上本地工作正常。
您的方法可能最适合重组。您应该重新构建数据,以便您的值具有_id
自己的集合和引用。在这个原因中,我会将引用存储在值集合中。
从此集合中删除values
字段
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar'
}
值模型:
{
y: Number,
x: Date,
parentId: {type: ObjectId, ref: "myColl"} //make sure you require ObjectId and rename the reference
}
然后你可以做这样的事情
ValuesModel.find({
x: mTime1
}).exec(function(err, results) {
var ids = {}; //hashMap to group values
var idsArr = []; //array of ids
results.forEach(function(item) {
if(!ids.hasOwnProperty(items.parentId.toString())) {
ids[items.parentId.toString()] = [];
idArr.push(item.parentId);
}
ids[items._id.toString()].push(item);
});
myColl.find({_id:{$in: idsArr}})
.exec(function(err, items) {
var results = items.map(function(item) {
item.values = ids[item._id.toString()];
return item;
});
done(results); //callback results
});
});
这将获取您查询的所有值,然后将它们分组到hashMap中并将所有parentId推送到数组。然后我查询该parentIds数组。我使用hashMap,通过hashMap中的id引用它,并在父文档中为.values
创建一个新字段。这将阻止您必须使用不可扩展的聚合,并允许您轻松查询值表。如果只想找到一个值,可以使用mongoose populate方法。这种方法的缺点是你需要在代码中做更多的工作,并且你有2次往返。但是,这应该比聚合更有效。
如果您经常查询值
,这可以用来创建一个可重用的方法来简化代码function queryValues(query, done) {
ValuesModel.find(query).exec(function(err, results) {
if(err) return done(err);
var ids = {}; //hashMap to group values
var idsArr = []; //array of ids
results.forEach(function(item) {
if(!ids.hasOwnProperty(items.parentId.toString())) {
ids[items.parentId.toString()] = [];
idArr.push(item.parentId);
}
ids[items._id.toString()].push(item);
});
myColl.find({_id:{$in: idsArr}})
.exec(function(err, items) {
if(err) return done(err);
var results = items.map(function(item) {
item.values = ids[item._id.toString()];
return item;
});
done(null, results); //callback results
});
});
}
然后你可以调用queryValues({x: mTime1}, function(err, results){...});
,你可以传递你想要的任何查询,该函数将处理填充父文档而不需要获取重复数据以获得最大效率。
我可能还建议您在模型定义中将此方法定义为模式静态方法,这样您就可以将这些代码丢弃,而不必担心。请参阅:http://mongoosejs.com/docs/api.html#schema_Schema-static