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],
});
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);
}
};
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 }
});
not an elagant but a better solution than the first one
const creatStock = async (symbol, webApiData) => {
try {
const query = { symbol };
const update = { $addToSet: { data: webApiData } };
const options = { upsert: true, new: true };
const stockResult = await Stock.findOneAndUpdate(query, update, options);
const newOpen = webApiData[0].open.toString();
const newHigh = webApiData[0].high.toString();
const newLow = webApiData[0].low.toString();
const newClose = webApiData[0].close.toString();
const newVolume = webApiData[0].volume.toString();
stockResult.data[0].open = newOpen;
stockResult.data[0].high = newHigh;
stockResult.data[0].low = newLow;
stockResult.data[0].close = newClose;
stockResult.data[0].volume = newVolume;
await stockResult.save();
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.