I have a Node.js API with MongoDB. The ODM is Mongoose. The MongoDB collection is called 'Battery'. It stores data, coming from multiple IoT devices. Each document has a "BAT" array. This array has only a single object. There are about 100000 documents here. A new data is created every 4 minutes. There are multiple "SID" values such as "S044","S067",etc. There may be 10 to 2000 unique "SID" values. Each "SID" belongs "BID" values starts from 1 to "BYC/BXC" value. Below shows how they appear as a JSON data. In below example "BYC/BXC" value is 12. Then for "SID":"S044", there should be 12 unique documents which have "BID" value from 1 to 12 (It is better to use the latest document for a particular "SID" to calculate "BYC/BXC" value and need to retrieve latest documents for that "SID". Each "SID" has different "BYC" and "BXC" values. "BXC" and "BYC" values are unique for a particular "SID".
{
"TS": "1680047000007",
"SID": "S044",
"BAT": [
{
"BID": 9,
"FOC": 1,
"BXC": 100,
"BYC": 1200
}
]
},
{
"TS": "1680000605007",
"SID": "S044",
"BAT": [
{
"BID": 7,
"FOC": 1,
"BXC": 100,
"BYC": 1200
}
]
},....more
Currently I have created a query as below;
const getLatestBats = async (all_SIDs) => {
const distinctSIDs = await Battery.distinct("SID", { SID: { $in: all_SIDs } });
const latestDocuments = [];
for (const SID of distinctSIDs) {
const batteryDoc = await BAT.findOne({ SID })
.select("BAT")
.sort({ TS: -1 });
if (batteryDoc && batteryDoc.BAT && batteryDoc.BAT.length > 0) {
const { BYC, BXC } = batteryDoc.BAT[0];
const BatCount = BYC / BXC;
const documents = await Battery.aggregate([
{ $match: { SID, "BAT.BID": { $in: [...Array(BatCount)].map((_, index) => index + 1) } } },
{ $sort: { TS: -1 } },
{ $group: { _id: "$BAT.BID", document: { $first: "$$ROOT" } } },
{ $replaceRoot: { newRoot: "$document" } },
{ $project: { _id: 0, __v: 0 } },
]);
latestDocuments.push(...documents);
}
}
return { data: latestDocuments};
};
router.get('/', async (req, res) => {
try {
<-----all_SIDs come through a middleware---->
const batteries = await getLatestBats(all_SIDs);
res.json(batteries);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error' });
}
});
module.exports = router;
. But, it takes about 8 seconds to return the response and also it required to create a const latestDocuments = []; array to store matching documents. But, it is not a good practice because can not use pagination(limit,page) for this array. I need to build a query or aggregation with overcoming these issues.
These are two documents from the collection (to get idea of the schema model).
_id 6483ea992dae73e915e14575
TS "1686366869373"
SID "CM045"
BAT Array 0 Object
BID 1
BXC 100
BYC 500
__v 0
_id 6483ea9f2dae73e915e14578
TS "1686366879348"
SID "CM045"
BAT Array 0 Object
BID 4
BXC 100
BYC 500
__v 0