0

Ok I am confused. I am trying to find documents using the $function operator as described here: S_function.

My model:

const newsSchema = new mongoose.Schema({
news_id: {
    type: mongoose.Schema.Types.ObjectId,
    unique: true,
    index: true
},
created_at: { type: String, default: Date.now().toString() },
updated_at: { type: String, default: Date.now().toString() },
Company_id: [{type: mongoose.Schema.Types.ObjectId}],
Stock_id: [{type: mongoose.Schema.Types.ObjectId}],
newsItem: {
    date: {type: String},
    title: { type: String },
    summary: { type: String },
    url: { type: String, unique: true },
    content: { type: String }
}
};

My code attempt:

newsModel.aggregate([
        {$match: {$function: {
            body: matchArrToArr(matchArr, Company_id),
            args: [ "$Company_id" ],
            lang: "js"
         }}}
    ])

matchArr is a variable I pass in from the surrounding function and Company_id is supposed to be the array 'Company_id' from the news document. However when I execute the function, the error 'Company_id is not defined' is returned. Which makes sense, as I dont define it but how do I get the Company_id field into the function.

I also tried find($expr:{$function:... with the same result and $where:... with this.Company_id. First case same error. Second case 'this' has the state of my calling JS function and not the DB document.

What I am actually trying to do: I want to return all documents, where one of the ids in the Company_id array matches one of the ids I pass in. If there is a nicer aggregate way without $function, I am open to that. But I also want to understand what I am doing wrong with my $function expression.

Thanks!

3
  • 1
    Function declaration and function invocation are two different this. You need to define a function not invoke it. MongoDB will invoke the function you passed it as an argument to body property. Do not call matchArrToArr function. Replace it with function definition. Commented Feb 27, 2021 at 12:21
  • 1
    Update the question with your attempt. If still not working I will help u. Commented Feb 27, 2021 at 12:24
  • Omg yes you are completely right, stupid me. Maybe my 3 days no food is showing. Thanks a lot! Commented Feb 27, 2021 at 13:30

1 Answer 1

1

This is what you want:

let someCompany_id = "60278ce8b370ff29b83226e7";

db.news.find(
    {
        $expr: {
            $function: {
                body: function(company_ids, someCompany_id) {
                    let _ids= company_ids.map(company_id => company_id.valueOf());
                    return _ids.includes(someCompany_id);
                },
                args: ["$company_id", someCompany_id],
                lang: "js"
            }
        }
    }
)

But this can be done easily like this:

db.news.find({ 
    company_id: {
        $in: [someCompany_id]
    }
});

So why do you want to pass function?

Sign up to request clarification or add additional context in comments.

1 Comment

Yes I was calling instead of passing the function. As usual when I am stuck it is the dumbest of mistakes. The reason I cannot just do a simple find is that both input and match IDs are arrays and I want a match if just one of them matches. So [someId1,someId2] and [someId2, someId3] should return true,

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.