How to conditionally findOneAndUpdate with objects?

Hi,
I’m working on a project where I can only allow so many “searches” per a month (30 days) per user. Specifically, what I was trying to do was have the document conditionally update where if the searches.date was less than 30 days from the thirty value searches.date became today’s value and searches.number went back to 0, else searches.number increased by 1, but if searches.date was null then searches.date became today and searches.number became equal to 1. I was able to do something similar with arrays, but I can’t figure out how to get this to work with objects. I would really appreciate any help or advice. Thank you!

let today = new Date()
let thirty = new Date()
thirty.setDate(thirty.getDate() - 30);

  const possible = await UserInfo.findOneAndUpdate({_id:user._id}, 
                [
                    {
                        $set: {
                            searches: {
                                $cond: {
                                    if: {"searches.date":{$lte: +thirty}},
                                    then: {{"searches.date":+today, "searches.number": 0}]},
                                    else: {$ifNull: [{ $inc:{"searches.number":1}}, 
                                    {"searches.date":+today,"searches.number":1}]},
                                }
                            },
                        }
                    },
                ],
  {upsert: true})

Schema

function timestamp() {
    return +new Date();
  }

const SearchesSchema = new mongoose.Schema({
    number: Number,
    date: {type:Number, default: timestamp}
})
const UserInfoSchema = new mongoose.Schema({
    _id: {
        type:mongoose.Schema.Types.ObjectId, ref:'User'
    },
    searches: SearchesSchema,
    info: [InfoSchema]
})

Playing just in the shell, something like this?

db.UserInfo.findOneAndUpdate(
{
    _id:"john"
},
[
    {
        $set:{
            searches:{
                $cond: {
                    if: {$lte:["$searches.date", thirty]},
                    then: {"date":today, "number": 0},
                    else: {
                        "date":today, 
                        "number": {$add:[{$ifNull:["$searches.number", 0]},1]}
                    }
                } 
            }
        }
    },
],
{upsert: true}
)

Note adding square brackets to enable aggregation statements in the update section.

When doing this kind of thing I find it useful to start with an aggregation in the shell and build the update from there:

db.UserInfo.aggregate([
{
    $addFields:{
        newData:{
            $cond: {
                if: {$lte:["$searches.date", thirty]},
                then: {"date":today, "number": 0},
                else: {
                    "date":today, 
                    "number": {$add:[{$ifNull:["$searches.number", 0]},1]}
                }
            }            
        }
    }
}
])

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.