Invalid callback() argument error with Mongoose - javascript

I have a collection like this (very simplified)...
var parentSchema = new mongoose.Schema({
firstName: String,
mobile: String
});
var familySchema = new mongoose.Schema({
groupId: { type: mongoose.Schema.Types.ObjectId, index: true },
parents: [parentSchema]
});
For a given group, I'd like to find all of the parents of families in that group who have a mobile value set (exists), and unset those mobile values.
I've been able to piece this much together by looking at other examples...
Family.update(
{ groupId: someGroupId, "parents.mobile": {"$exists":"true"} },
{ $unset : { "parents.$.mobile" : 1 } }, false, true
).then(function() {
// do other stuff
});
Running generates the error:
Trace: [Error: Invalid callback() argument.]
I've tried several variations, but this one seems the most correct to me.

The .update() signature for mongoose models is:
Model.update(<{query}>,<{update}>,[<{options}>],[callback])
So when using promises, it's just the first two with the optional "third" options. The "fourth" would be a callback function, and hence the error:
Family.update(
{ "groupId": someGroupId, "parents.mobile": {"$exists": true } },
{ "$unset": { "parents.$.mobile" : "" } },
{ "multi": true }
).then(function() {
Too many people read the "shell" signature, even though the usage of:
.update(<{query}>,<{update}>,<upsert>,<multi>)
Has been deprecated in favour of the standard "options" arrangement for some time.
Always refer to the method that actually applies to your language API.

Related

Mongoose findOne sending null

I am trying to edit a discord bot made in python (I stored data initially in python) and transferring it to javascript (node.js) and can't feature out while connecting to my old db why findOne giving me null while providing proper discord id.
Without anything inside
Code
anifarm.findOne();
Output
{
_id: 707876147324518400,
farmed: 17,
ordered: 5,
pimage: 'https://media.tenor.com/images/e830217a5d9926788ef25119955edc7f/tenor.gif',
pstatus: 'I want you to be happy. I want you to laugh a lot. I don’t know what exactly I’ll be able to do for you, but I’ll always be by your side.',
avg: 184,
speed: 2,
badges: [
'https://cdn.discordapp.com/attachments/856137319149207563/856137435696332800/Black-and-Yellow-Gaming-Badge--unscreen.gif',
'https://cdn.discordapp.com/attachments/856137319149207563/862219383866523688/Front-removebg-preview.png', 'https://cdn.discordapp.com/attachments/856137319149207563/862240758768599100/download-removebg-preview.png'
],
setBadges: 'https://cdn.discordapp.com/attachments/856137319149207563/862240758768599100/download-removebg-preview.png'
}
With id inside
Code
anifarm.findOne({
_id: 707876147324518400
});
Output
null
anifarm in the schema.
Decleared Schema
module.exports = mongoose.model('anifarm', new mongoose.Schema({
_id: Number,
farmed: {
type: Number,
default: 0
},
ordered: {
type: Number,
default: 0
},
pimage: {
type: String,
default: ""
},
pstatus: {
type: String,
default: ""
},
avg: {
type: Number,
default: 200
},
speed: {
type: Number,
default: 2
},
badges: {
type: Array,
default: []
},
setBadges: {
type: String,
default: ""
}
},
{
collection: 'anifarm',
versionKey: false
})
);
I cannot figure out what am I doing wrong. This problem also happens with .find()
Nothing inside find fetches everything by if I provide id it sends a empty array.
A Little help would be appreciated
For you problem use mongoose-long that should fix your problem.
This library will handle all long type data for mongoose since mongoose cannot handle long type data
you can't pass an id as a number, you will have to use ObjectId to convert the id to an instanceof ObjectId
Change your code like this
anifarm.findOne({
_id: mongoose.Types.ObjectId(707876147324518400);
});
If you're querying by _id, use findById() instead.
anifarm.findById("707876147324518400")
Official docs here

MongoDB/Mongoose - Adding an object to an array of objects only if a certain field is unique

So I have a nested array of objects in my MongoDB document and I would like to add a new object to the array only if a certain field (in this case, eventId) is unique. My question is very similar to this post, only I cannot seem to get that solution to work in my case.
Here is what the documents (UserModel) look like:
{
"portal" : {
"events" : [
{
"important" : false,
"completed" : false,
"_id" : ObjectId("5c0c2a93bb49c91ef8de0b21"),
"eventId" : "5bec4a7361853025400ee9e9",
"user_notes" : "My event note"
},
...and so on
]
}
}
And here is my (so far unsuccessful) Mongoose operation:
UserModel.findByIdAndUpdate(
userId,
{ "portal.events.eventId": { $ne: req.body.eventId } },
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);
Basically I am trying to use '$ne' to check if the field is unique, and then '$addToSet' (or '$push', I believe they are functionally equivalent in this case) to add the new object.
Could anyone point me in the right direction?
Cheers,
Gabe
If you look into the documentation on your method you will see that the parameters passed are not in the proper order.
findByIdAndUpdate(id, update, options, callback)
I would use update instead and have your id and portal.events.eventId": { $ne: req.body.eventId } part of the initial filter followed by $addToSet: { "portal.events": req.body }
Something among these lines:
UserModel.update(
{
"_id": mongoose.Types.ObjectId(userId),
"portal.events.eventId": { $ne: req.body.eventId }
},
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);
You need to include your eventId check into condition part of your query. Because you're usig findByIdAndUpdate you can only pass single value matched against _id as a condition. Therefore you have to use findOneAndUpdate to specify custom filtering condition, try:
UserModel.findOneAndUpdate(
{ _id: userId, "portal.events.eventId": { $ne: req.body.eventId } },
{ $addToSet: { "portal.events": req.body } },
{ new: true }
);

Model not associated with Model Sequelize

I'm trying to esatblish a One-To-Many relationship between the tables: Exam and Exam_Questions, using Sequelize.
Even though the tables are created properly and I can see them in PhpMyAdmin, I keep getting the following error in console:
Error: exam_question is not associated to exam!
exam.js
...
const ExamQuestion = require('./exam-question');
...
const Exam = sequelizeInstance.define("exam", {
name: { type: Sequelize.STRING },
date: { type: Sequelize.DATE }
});
// Build the model relations
Exam.hasMany(ExamQuestion, { as: "Questions" });
exam-question.js
const ExamQuestion = Sequelize.db.define("exam_question", {
correct_answer: {
type: Sequelize.STRING
},
text: {
type: Sequelize.STRING
}
});
module.exports = ExamQuestion;
To solve the error, I tried:
ExamQuestion.belongsTo(Exam);
But that doesn't change anything.
The query is:
Exam.findAll({
include: [ExamQuestion]
})
How to fix this problem and get the Exam objects including their questions?
TL;DR
For some very non-intuitive reason this seems to be happening because of the as property. To fix the problem, simply remove the as property:
Exam.hasMany(ExamQuestion);
Fixing the methods
By default, after removing the as property, Sequelize will automagically add the following methods: getExam_questions, addExam_question and so on.
They look quite bad: camel and snake cases mixed up together.
To solve that, we can easily define the singular and plural names in the ExamQuestion model options (the third argument):
const ExamQuestion = Sequelize.db.define("exam_question", {
correct_answer: {
type: Sequelize.STRING
},
text: {
type: Sequelize.STRING
}
}, {
name: {
singular: "question",
plural: "questions"
}
});
This will dictate Sequelize to create methods such as getQuestions and addQuestion instead of getExam_questions and addExam_question.

Query with OR conditions, mongodb/mognoose

This is (a part) of my model:
var materialSchema = new Schema({
ownerType: { type: String, required: true},
organization: {
type: Schema.ObjectId,
ref: 'organization'
},
user: {
type: Schema.ObjectId,
ref: 'users'
},
});
I want to make a query that returns:
ownerType = 'public'
organization = 321
The condition are 'OR'. So the material should be either ownerType 'public' or organization 321.
Can not find this in the docs. Do I need to make nested queries with "find" to do this? Or can it be done with a single query?
Some pseudo code:
mongoose.model('material').find({ownerType:'public' || organization:321}, function(err,materials){
...
}
Well presuming that your actual "Model" is named Material then you would come out to something like this in MongoDB parlance:
Material.find(
{
"$or": [
{ "ownerType": "public" },
{ "orginization._id": 123 }
]
},
function(err,docs) {
// results in here
}
);
So MongoDB has an $or operator, which makes sense since the query operands are represented in BSON ( from JSON conversion in the JavaScript case ). The purpose presents an "array" of possible arguments which are evaluated in a "short circuit" manner to determine if either case results in a true condition to match your query criteria.

MongoDB findAndModify not working with monk

I am trying to use findAndModify with the node.js mongodb module monk.This is the method that I am using,this throws a 500 error in my cmd:
notesCollection.findAndModify({_id:_id},[],{_id:_id,title:title,content:content},{'new':true,'upsert':true},function(err,doc){
if(err)
console.error(err);
else
{
console.log("Find and modify successfull");
console.dir(doc);
}
});
I obtained the method signature here.I get an error that looks like this and is uninformative:
POST /notes/edit/542bdec5712c0dc426d41342 500 86ms - 1.35kb
Monk implements methods that are more in line with the shell syntax for method signatures than what is provided by the node native driver. So in this case the "shell" documentation for .findAndModify() is more appropriate for here:
notescollection.findAndModify(
{
"query": { "_id": id },
"update": { "$set": {
"title": title,
"content": content
}},
"options": { "new": true, "upsert": true }
},
function(err,doc) {
if (err) throw err;
console.log( doc );
}
);
Also noting that you should be using the $set operator or posibly even the $setOnInsert operator where you only want fields applied when the document is created. When operators like this a re not applied then the "whole" document is replaced with whatever content you specify for the "update".
You also don't need to supply the "_id" field in the update section, as even when an "upsert" occurs, anything present in the "query" portion of the statement is implied to be created in a new document.
The monk documentation also hints at the correct syntax to use for the method signature.
Had the same problem, and even though I liked it, the accepted answer didn't work for me.
It's not clear enough, but the documentation hints at the correct syntax, starting with the signatures:
All commands accept the simple data[, …], fn. For example
findAndModify({}, {}, fn)
And from the finding section:
users.findAndModify({ _id: '' }, { $set: {} });
Finally, continuing with the signatures section:
You can pass options in the middle: data[, …], options, fn
Putting it all together:
collection.findAndModify({
_id: '',
}, {
$set: {
value: '',
},
}, {
upsert: true,
});
So in this case, data[, …] is the couple {}, {} objects: query and update. Then you can add the callback as a 4th parameter in my snippet.

Categories