描述: 格式如下所示,其中每个对象有_id,name,和一个数组scores,其中可以看到修改前的数组中,每个document有两个type为"homework"的对象。
*提问*: 问题是如何操纵mongo数据库,批量修改db.students,让每个document中,删除score较小的homework,而保留score较大的homework。
修改前:
{
"_id" : 100,
"name" : "Demarcus Audette",
"scores" : [
{
"score" : 47.42608580155614,
"type" : "exam"
},
{
"score" : 44.83416623719906,
"type" : "quiz"
},
{
"score" : 19.01726616178844,
"type" : "homework"
},
{
"score" : 39.01726616178844,
"type" : "homework"
}
]
}
修改后:
{
"_id" : 100,
"name" : "Demarcus Audette",
"scores" : [
{
"score" : 47.42608580155614,
"type" : "exam"
},
{
"score" : 44.83416623719906,
"type" : "quiz"
},
{
"score" : 39.01726616178844,
"type" : "homework"
}
]
}
下面附上一段nodejs上跑的代码(自己写的,有问题跑不通,作为参考):
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/school', function(err, db){
if(err) throw err;
var query = {};
var cursor = db.collection('students').find(query);
cursor.each(function(err, doc){
if(err)throw err;
if(doc == null){return db.close();}
/*TODO*/
var target1 = doc.scores[2];
var target2 = doc.scores[3];
if(target1 < target2) doc.update({$unset: target1});
else doc.update({$unset: target2});
console.dir("Successfully found " + target1);
});
});
黄舟2017-04-17 11:12:39
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://school:school@localhost:27017/school', function(err, db) {
if (err) {
throw err;
}
var student = db.collection('students');
var updateData = function(newdoc) {
//把旧的删除
student.findAndRemove({_id: newdoc._id}, function(err, olddoc) {
if (err) {
throw err;
}
olddoc && console.log('remove olddoc id: %s', olddoc._id);
//插入新的
student.insert(newdoc, function(err, saveResult) {
if (err) {
throw err;
}
saveResult && console.log('[OK] update ok , id: %s', newdoc._id);
saveResult || console.log('[ERR] update fail, id: %s', newdoc._id);
});
});
};
//插入测试数据
student.insert([
{
name: 'hehehe',
scores: [
{
score: 97.42608580155614,
type: 'exam',
},
{
score: 14.83416623719906,
type: 'quiz',
},
{
score: 55.01726616178844,
type: 'homework',
},
{
score: 3.0172661617884,
type: 'homework',
}
],
},
{
name: 'Demarcus Audette',
scores: [
{
score: 47.42608580155614,
type: 'exam',
},
{
score: 44.83416623719906,
type: 'quiz',
},
{
score: 19.01726616178844,
type: 'homework',
},
{
score: 39.0172661617884,
type: 'homework',
}
],
},
], function(err, result) {
if (err) {
throw err;
}
//聚合
student.aggregate([
{$unwind: '$scores'},
{$group: {
'_id': {
'_id': '$_id',
name: '$name',
type: '$scores.type',
},
score: {
'$max': '$scores.score'
}
}},
{$project: {
'_id': {
_id: '$_id._id',
name: '$_id.name',
},
scores: {
type: '$_id.type',
score: '$score',
},
}},
{$group: {
'_id': '$_id',
scores: {
'$push': '$scores',
}
}}
], function(err, result) {
if (err) {
throw err;
}
//循环结果
result.forEach(function(item) {
item = {
_id: item._id._id,
name: item._id.name,
score: item.scores
};
updateData(item);
});
});
});
});
阿神2017-04-17 11:12:39
I guess what you want is in place update, such as findAndEval and similar methods, and then you will be disappointed
https://jira.mongodb.org/browse/SERVER-458
So far it has not been implemented and is listed in Planning Bucket B. The visual realization is far away.
Well, the lack of implementation mentioned above means that it cannot be completed on the server side (the relationship between mongo and mongod)
If it is done on the client side, you can use the cursor.forEach method, such as
db.students.find().snapshot().forEach(
function (e) {
e.删除score较小的homework!;
db.students.save(e);
}
)