Search code examples
node.jsmongodbmongooseaggregation-frameworkinsert-update

mongoose: findOneAndUpdate find more complicated expression than _id


I want to find a document, that matches some calculated ID and then looks if the timestamp is younger than 15 minutes. If thats the case and a doc is found, I want to update the document with the req.body. Otherwise, if it's older than 15 minutes, or no document is found, I want to create a new document with the req.body.

Now my question is, should I use static findOneAndUpdate method or is it too unflexible for my purpose? I was using aggregation framework, can it do those type of stuff, like update fields and / or set fields if they are not existant yet? This is my aggregation pipeline to look for the doc ID and timestamp less than 15 minutes:

exports.calcID = function(req,res) {
        console.log("Call aggregation stage..:")        

        Flex.aggregate([        
            {
                $addFields: {
                    subID:  {
                        "$eq": [{"$trunc": {"$divide": ["$_id", 1000000]}}, +req.params.demo_id]                    
                    },
                    rightTime: {
                        "$gte": ["$createdAt", new Date(+new Date()- 60*1000*15)]
                    }
                }
            },      
            {
                "$match": { 
                    subID:true,
                    rightTime:true

                }
            },
            {
                "$sort": {"Timestamp":-1}
            },
            {
                "$limit": 1
            },
            {
                "$project": {subID:0, rightTime:0}
            }
        ]).exec(function(err, flPot) {
            console.log(flPot);
            console.log("Anzahl gefundener Dokumente: ", flPot.length)      
            if (flPot.length == 0) {
                res.end("Keine Dokumente juenger 15 Minuten gefunden!")
                var flex = new FlexPotenzial(req.body);     
                flex.save(function(err) {
                if (err) {
                    console.log(err);
                    res.status(400);
                    res.send(err);
                }
                else {              
                    console.log("Instanz FlexPotenzial in Datenbank erzeugt!");
                    res.status(200);
                    res.json({ message: 'FlexPotenzial-Instance created in datbase!\n', flex });
                }
                })
            }
            else if (flPot.lengh!==0) {
                    flPot.Timestamp = req.body.Timestamp;
                    flPot.aktThErzeugungsleistungWaerme = req.body.aktThErzeugungsleistungWaerme;
                    flPot.aktThNachfrageleistungWaerme = req.body.aktThNachfrageleistungWaerme;
                    flPot.aktThErzeugungsleistungGas = req.body.aktThErzeugungsleistungGas;
                    flPot.aktThNachfrageleistungGas = req.body.aktThNachfrageleistungGas;
                    flPot.aktLeistungsuntergrenze = req.body.aktLeistungsuntergrenze;
                    flPot.aktLeistungsobergrenze = req.body.aktLeistungsobergrenze;
                    flPot.BrennRohstoffbezug = req.body.BrennRohstoffbezug;
                    flPot.Produktstrom = req.body.Produktstrom;
                    flPot.Dummy1 = req.body.Dummy1;
                    flPot.Dummy2 = req.body.Dummy2;
                    flPot.Dummy3 = req.body.Dummy3;
                    flPot.Dummy4 = req.body.Dummy4;

                    flPot.save(function(err) {
                        if (err) {
                            console.log(err);
                            res.status(400);
                            res.send(err);
                        }
                        else {              
                            console.log("FlexPotenzial aggregierte Daten in Datenbank aktualisiert!");
                            res.status(200);
                            res.json({ message: 'FlexPotenzial-Instance aggregated data updated!\n', flex });
                        }
                    }
                )
            }
        });
    }

I don't know whats the best approach here and how to check after docs are found or not, how to update the fields, and if no docs are found, how to create new docs in aggregation or in a separate function then...


Solution

  • I assume you divide your stored ID to get a range of IDs. Why not do that in a query :

    const minID = req.params.demo_id * 1000000;
    const maxID = (req.params.demo_id + 1) * 1000000;
    const fifteenMinutesAgo = new Date(Date.now() - 15*3600*1000)
    Flex.findOneAndUpdate({
      _id: { $gte: minID, $lt: maxID },
      createdAt: { $gte: fifteenMinutesAgo }
    }, { $set: req.body })
    

    Of course, you should sanitize your inputs, not just throw req.body in.

    If the ID calculation is more complicated than what you put in this snippet, consider storing it in your document.