问题
I use MongoDB native driver in my NodeJS application.
I have a shifts
collection in my database that I need to update. Sample docs in my shifts collection
{
"_id" : ObjectId("588425105560bd2ba0065fa4"),
"from" : ISODate("2017-01-23T03:20:00.000Z"),
"to" : ISODate("2017-01-23T06:20:00.000Z"),
"jobId" : ObjectId("586efda790541421b0432897"),
"hourlyRate" : 15
}
{
"_id" : ObjectId("588425105560bd2ba0065fa5"),
"from" : ISODate("2017-01-25T03:20:00.000Z"),
"to" : ISODate("2017-01-25T06:20:00.000Z"),
"jobId" : ObjectId("586efda790541421b0432897"),
"hourlyRate" : 15
}
What I need to do is the following -
Update the hourlyRate
of all docs that meet the conditions:
- match the jobId (that is easy)
- set
hourlyRate
= 20 iffrom
is a Weekday - set
hourlyRate
= 25 iffrom
is a Saturday - set
hourlyRate
= 30 iffrom
is a Sunday
I would want to do it in a single query as far as possible.
My solution so far:
Use switch case and determine the type of day using $dayOfWeek
from Date aggregation function. However, I am not able to combine switch with updateMany
.
Any help would be appreciated.
回答1:
You could run the following aggregation pipeline with special operators at your disposal like $switch which is new in MongoDB Server 3.4 and above:
MongoDB Server 3.4:
db.collection('shifts').aggregate([
{
"$match": {
"jobId": ObjectId(job._id),
"from": { "$gte": new Date() }
}
},
{
"$project": {
"hourlyRate": {
"$switch": {
"branches": [
{
"case": {
"$not": {
"$in": [
{ "$dayOfWeek": "$from" },
[1, 7]
]
}
},
"then": 20
},
{
"case": {
"$eq": [
{ "$dayOfWeek": "$from" },
7
]
},
"then": 25
},
{
"case": {
"$eq": [
{ "$dayOfWeek": "$from" },
1
]
},
"then": 30
}
]
}
}
}
}
], function(err, docs) {
var ops = [],
counter = 0;
docs.forEach(function(doc) {
ops.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "hourlyRate": doc.hourlyRate } }
}
});
counter++;
if (counter % 500 === 0) {
db.collection('shifts').bulkWrite(ops, function(err, r) {
// do something with result
});
ops = [];
}
})
if (counter % 500 !== 0) {
db.collection('shifts').bulkWrite(ops, function(err, r) {
// do something with result
}
}
});
MongoDB Server 3.2
db.collection('shifts').aggregate([
{
"$match": {
"jobId": ObjectId(job._id),
"from": { "$gte": new Date() }
}
},
{
"$project": {
"hourlyRate": {
"$cond": [
{
"$not": {
"$setIsSubset": [
[{ "$dayOfWeek": "$from" }],
[1, 7]
]
}
}, 20,
{
"$cond": [
{ "$eq": [
{ "$dayOfWeek": "$from" },
7
] },
25,
{
"$cond": [
{ "$eq": [
{ "$dayOfWeek": "$from" },
1
] },
30,
"$hourlyRate"
]
}
]
}
]
}
}
}
], function(err, docs) {
var ops = [],
counter = 0;
docs.forEach(function(doc) {
ops.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "hourlyRate": doc.hourlyRate } }
}
});
counter++;
if (counter % 500 === 0) {
db.collection('shifts').bulkWrite(ops, function(err, r) {
// do something with result
});
ops = [];
}
})
if (counter % 500 !== 0) {
db.collection('shifts').bulkWrite(ops, function(err, r) {
// do something with result
}
}
})
来源:https://stackoverflow.com/questions/41787787/update-multiple-docs-in-a-collection-using-switch-case