Ok that question doesn't sound very clear. I will try to explain. I have a collection of F1 drivers that contains an array field to store the points earned from each race. I use a web form to submit the full result of a given race that contains the race_id, race_name, and a positions array that contains the driver_id and points earned as an object for each driver. I now need to update each driver in the collection with their result from this race by matching the driver id with the id in the object array. Ultimately; I will also need to update the total_points for each driver, but that can wait for now.
// The handler for my web form
function handleRaceResultSubmit(e) {
e.preventDefault();
let positions = [{id: null, points: 25}, {id: null, points: 18},{id: null, points: 15},{id: null, points: 12},{id: null, points: 10},
{id: null, points: 8},{id: null, points: 6},{id: null, points: 4},{id: null, points: 2},{id: null, points: 1},
{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},
{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},{id: null, points: 0},];
const eventID = parseInt(document.querySelector('#event-select').value);
const eventName = document.querySelector('#event-select').textContent;
const selectGroup = document.querySelectorAll('.select-group');
selectGroup.forEach((driver, index) => {
positions[index].id = parseInt(driver.value);
})
const raceResult = {
event_id: eventID,
event_name: eventName,
result: positions
}
updateDriverResults(raceResult);
}
// Post result to the endpoint
const updateDriverResults = async (data) => {
fetch('driver-points',
{
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(data)
}).then(res => {return res.json()})
.then(data => console.log(data))
.catch(error => console.log(error));
}
//My endpoint and Mongoose query
app.post('/driver-points', express.json(), (req, res) => {
Drivers.updateMany({
'id': { $in: [ req.body.result.id ] },
},
{
$push: {'results': {
'event_id': req.body.event_id,
'event_name': req.body.event_name,
'points': req.body.result.points
}}
})
.then((result) => {
res.send(result);
})
.catch((error) => {
console.log(error);
})
})
// The model
import { mongoose } from "mongoose";
const Schema = mongoose.Schema;
const driversSchema = new Schema({
id: Number,
driver_name: String,
totla_points: Number,
results: Array
});
const Drivers = mongoose.model('driver', driversSchema);
export { Drivers };
Just to give you a rough idea on how to solve this, I have prepared a sample in mongoplayground that shows how you can use an update with aggregation pipeline to perform complex updates for documents. Let's assume that there are 3 drivers in your collection with _id
1, 2 and 3. Drivers 1 and 2 already have some points from the first race whereas driver 3 does not have any results up to now.
In the next race, drivers 1 and 3 reached points, so these two drivers should be updated so that
results
field is initialized as an empty array if it is not present yet,results
array,_id
is removed from the results
field andtotal
field should be updated with the total number of points.The sample assumes that there is an array with the _id
s of the drivers that should be updated ([1, 3]
) and also an array that contains the results:
[
{
_id: 1,
race_id: 2,
race_name: "Spa",
points: 7
},
{
_id: 3,
race_id: 2,
race_name: "Spa",
points: 3
}
]
The following update statement is used to perform the updates:
db.collection.update({
_id: {
$in: [
1,
3
]
}
},
[
{
$set: {
results: {
$ifNull: [
"$results",
[]
]
}
}
},
{
$set: {
results: {
$concatArrays: [
"$results",
{
$filter: {
input: [
{
_id: 1,
race_id: 2,
race_name: "Spa",
points: 7
},
{
_id: 3,
race_id: 2,
race_name: "Spa",
points: 3
}
],
cond: {
$eq: [
"$$this._id",
"$_id"
]
}
}
}
]
}
}
},
{
$unset: "results._id"
},
{
$set: {
total: {
$sum: "$results.points"
}
}
}
],
{
multi: true
})
Please use this sample as a starting point that you can integrate into your mongoose environment.