我有一系列选民登记数据。采取以下形式:
voter = {
name: "Some name",
registrationDate: "2015-10-21T15:41:36+00:00",
votingHistory: ["2015-10-21T15:41:36+00:00", "2015-7-21T15:41:36+00:00"]
}
我需要能够检测votingHistory数组子集的大小。例如,这是我尝试过的一个查询:
voters.find({
votingHistory : { $all : {$size : { $gt : 8 }}, { $gt : "2015-7-21T15:41:36+00:00" }}
})
此查询的目的是查找2015-7-21之后至少有8张选票的所有选民。有没有办法让mongoose查询数组属性子集的大小?
例如,使用以下三个条目:
{
name: "name1",
VotingHistory: ["2015-10-21T15:41:36+00:00", "2013-7-21T15:41:36+00:00"]
},
{
name: "name2",
VotingHistory: ["2015-10-21T15:41:36+00:00", "2011-7-21T15:41:36+00:00"]
},
{
name: "name3",
VotingHistory: ["2013-10-21T15:41:36+00:00", "2011-7-21T15:41:36+00:00", "2009-10-21T15:41:36+00:00", "2010-7-21T15:41:36+00:00"]
}
我想找到VotingHistory数组中的2个或更多元素代表2013-7-21之后的日期。这个例子中只有名称1。
答案 0 :(得分:1)
对于有效的查询,我建议通过将表示日期的字符串文字更改为实际日期来修改您的mongoose模式。
您可以先在架构定义中修改此项,例如
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var voterSchema = new Schema({
name: String,
registrationDate: Date,
votingHistory: [Date]
});
var Voter = mongoose.model("Voter", voterSchema, "voters" );
完成后,您需要使用 Bulk Operations API
修改现有的收藏集,以利用您的更新。对于任何给定的mongoose模型,存在一个.collection访问器,它基本上访问"集合对象"来自底层"节点本机驱动程序"在哪个猫鼬实现自己。这样,您可以对registrationDate
字段为字符串
mongoose.connection.on("open", function(err, conn) {
var bulk = Voter.collection.initializeOrderedBulkOp();
var counter = 0;
Voter.find({"registrationDate": {"$type": 2} }, function(err, docs) {
async.each(docs, function(doc, callback) {
var regDate = new Date(doc.registrationDate),
history = doc.votingHistory.map(function (dt){
return new Date(dt);
});
bulk.find({"_id": doc._id}).updateOne({
"$set": {
registrationDate: regDate,
votingHistory: history
}
});
counter++;
if (counter % 1000 == 0) {
bulk.execute(function(err,result) {
bulk = Voter.collection.initializeOrderedBulkOp();
});
}
else {
callback();
}
},
// When everything's done
function(err) {
if ( counter % 1000 != 0 )
bulk.execute(function(err,result) {
console.log("more updates" );
});
console.log("done now");
}
});
});
完成更新后,您可以执行以下两种方法中的任何一种。
其中之一是使用 $where
运算符:
var voteDate = new Date(2015, 6, 21);
Voter.find({
"$where": "this.votingHistory.length > 8",
"votingHistory": { "$gt": voteDate }
}).exec(callback);
另一种方法是使用 dot notation 来"技巧" mongodb寻找至少有第9个votingHistory
数组元素的文档:
var voteDate = new Date(2015, 6, 21);
Voter.find({
"votingHistory.8": { "$exists": true },
"votingHistory": { "$gt": voteDate }
}).exec(callback);
对于基于 aggregation framework
的解决方案(基于日期是适当的MongoDB日期的假设),以下管道将为您提供所需的结果:
var voteDate = new Date(2015, 6, 21),
pipeline = [
{
"$project": {
"name": 1,
"registrationDate": 1,
"votingHistory": 1,
"numberOfVotes": { "$size": "$votingHistory" }
}
},
{
"$match": {
"numberOfVotes": { "$gt": 8 },
"votingHistory": { "$gt": voteDate }
}
}
];
// you can then use the aggregate
Voter.aggregate(pipeline)
.exec(function (err, results){
// access your results here
});
// or using the aggregation builder
Voter.aggregate()
.project({
"name": 1,
"registrationDate": 1,
"votingHistory": 1,
"numberOfVotes": { "$size": "$votingHistory" }
})
.match({
"numberOfVotes": { "$gt": 8 },
"votingHistory": { "$gt": voteDate }
})
.exec(callback);
答案 1 :(得分:0)
如果你愿意使用下面的mongo agrregation
,这是可能的db.voter.aggregate([
{$unwind:"$votingHistory"},
{ $match: {votingHistory:{$gt:'2015-7-21T15:41:36+00:00'}}},
{$group:{_id: {voterId:'$_id',name:'$name',registrationDate:'$registrationDate'}, count:{$sum:1}}},
{$match:{count:{$gt:2}}},
{$project:{_id:"$_id.voterId", name:"$_id.name", registrationDate:"$_id.registrationDate"}}
])