为了有效查询,我建议通过将表示日期的字符串文字更改为实际日期来修改您的猫鼬模式。
您可以先在架构定义处修改它,例如
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 访问器,它本质上从实现 mongoose 的底层“节点本机驱动程序”访问“集合对象”。有了这个,您可以对 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);