问题
I am trying to fetch every minute a web API data to MongoDB, save it and update when there is any change. The problem is the volume
(every field) field is updated only (happens after a new trading day starts) when the new date
is added to ChildSchemaData
- subdocumet. All this data is used to build a daily (NOT hourly/minute ) stock chart on front-end. And I am trying to stream it from database but since the volume
(and all other fields in subdocument) is not updated in database nothing is changing on front-end. I am trying to implemet change Streams MongoDB (data stream from database) so I insist on getting data from database. Any help is appreciated. Thank you!
Edit1: The $addToSet
operator adds a value to an array unless the value is already present, in which case $addToSet
does nothing to that array. It looks like that is the problem. I am wondering if there is a different operator that would update the value that is already present.
Edit2: I was playing around with the following syntax but not sure if it is correct
const update = {
$addToSet: { data: webApiData },
$set: { 'data[0].$.volume': webApiData[0].volume },
};
because it is getting into the same path
it is not going to work
Controller
const creatStock = async (symbol, webApiData) => {
try {
const query = { symbol };
const update = { $addToSet: { data: webApiData } };
const options = { upsert: true, new: true };
await Stock.findOneAndUpdate(query, update, options);
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}
};
Schema
const ChildSchemaData = new mongoose.Schema({
_id: false,
date: { type: mongoose.Types.Decimal128 },
open: { type: mongoose.Types.Decimal128 },
high: { type: mongoose.Types.Decimal128 },
low: { type: mongoose.Types.Decimal128 },
close: { type: mongoose.Types.Decimal128 },
volume: { type: mongoose.Types.Decimal128 },
});
const ParentSchemaSymbol = new mongoose.Schema({
symbol: {
type: String,
},
// Array of subdocuments
data: [ChildSchemaData],
});
回答1:
If you want to update an element in an array, you can consider the positional operator: $ and add the field to your update query.
This identifies an element in an array to update based on a condition.
Example to update the embedded array with a volume
field equal to 100 and set to 200:
db.getCollection("collection").findOneAndUpdate({
id: 1,
"data.volume": 100
},
{ $set: { "data.$.volume": 200 }
});
回答2:
This solution was provided by srinivasy at the following link link
const creatStock = async (symbol, webApiData) => {
try {
// reversed array
const webApiDataReversed = webApiData.reverse();
const query = { symbol };
const position = await Stock.findOne(query);
if (!position) {
console.log('New stock'.green);
return Stock.create({
symbol,
data: webApiDataReversed,
});
}
await Stock.bulkWrite([
{
updateOne: {
filter: query,
update: { $pop: { data: 1 } },
},
},
{
updateOne: {
filter: query,
update: {
$addToSet: {
data: webApiDataReversed,
},
},
},
},
]);
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}
};
来源:https://stackoverflow.com/questions/58942037/mongoose-findoneandupdate-does-not-update-an-existing-field