Title says it all. Below is a schema property definition that I thought would work, but doesn't do the job. I figured required: true on the type object should work?
users: {
type: [
{
type: Schema.Types.ObjectId,
ref: 'User',
required: true
}
],
default: []
}
the following query allows a null value to be added to the array:
MyModel.findByIdAndUpdate(id, {$addToSet: {users: ['']}})
aaaaaaaand, of course as soon as I post to SO, i find the answer for myself. need to set option runValidators: true on update...
This is the real reason I post to SO, its like always carrying an umbrella, its guaranteed not to rain.
Related
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
I have this model and I want to do a sort where the requests are sorted in this order(estadoPedido:Pendente,estadoPedido:Agendado,EstadoPedido:Concluido)
Is that possible?
var requestSchema = new Schema({
paciente: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: [true, "paciente is a required field"],
},
encaminhado: {
type: Boolean,
required: [true, "encaminhado is a required field"],
}, //vem do body
pessoaRisco: {
type: Boolean,
required: [true, "pessoaRisco is a required field"],
}, //vem do body
trabalhoRisco: {
type: Boolean,
required: [true, "trabalhoRisco is a required field"],
}, //vem do body
estadoPedido: {
type: String,
enum: ["Pendente", "Agendado", "Concluído", "Aguarda Resultado"],
},
resultado: { type: String, enum: ["Positivo", "Negativo"] },
dataExame: {
type: Date,
},
prioridade: { type: Number },
});
Although there are solutions suggested here on Stack Overflow.
But the solutions as of now is to use aggregation pipeline, this approach can't be optimised with an index and requires a full collection scan to transform every document.
I would like to suggest an alternative workaround that might work well specifically for mongoose. But it does require data migration, but if you are still in early development, this is possible.
What you can do is modify your schema for estadoPedido:
estadoPedido: {
type: String,
enum: ["1_Pendente", "2_Agendado", "3_Concluído", "4_Aguarda", "5_Resultado"] // or use any other sortable prefix and separator symbol
index: true,
get(estadoPedido) {
const [, value] = estadoPedido.split('_') // this assumes you don't originally have _ in your enum
// or put your own logic to get your original value back
return value
}
}
Then when you want to query, you can just do
Request.find().sort({ estadoPedido: 1 })
mongoose will execute the get function and transform estadoPedido to original value on every document.
Warning
Keep in mind that this with this solution, you'll get the original value only in a mongoose document, when you use it somewhere else, e.g. in an aggregation, you will have to use the prefixed value
I have a schema that is defined like so:
const userSchema = new Schema({
...
surveys: [surveyKeySchema],
...
})
Where surveyKeySchema is actually a subdocument scheme defined like so:
const surveyKeySchema = new Schema({
slug: {
type: String,
required: 'Please supply a slug',
unique: true,
lowercase: true,
trim: true
},
name: {
type: String,
required: 'Please supply a name',
trim: true
},
responseCount: {
type: Number,
default: 0
}
})
Now whenever I try to modify anything on the user except for this array, everything goes fine. When instantiating the user, it is also totally fine. I can also call await user.save() in my code right before I empty the array.
It's also fine when I remove any subdocument from the survey as long as there is at least 1 element remaining.
However, when I try to remove the final subdocument using:
await user.surveys.id(sid).remove()
await user.save()
I get an error on the .save() which is just TypeError: Cannot read property '1' of null. I'm confused and can't find anything about this online, I assume it must be requiring at least one subdocument to be present? Is there any way to remove this, or if my assumption is wrong how would I go about resolving this?
Thanks in advance! And my apologies if I'm missing something obvious!
EDIT:
I found that mongoose's mongo error handler was actually throwing this in a regex it was using to parse the error message. Hacking this around to return the raw error message:
E11000 duplicate key error index: db.users.$surveys.slug_1 dup key: { : null }
As per this question I tried adding sparse: true but this didn't work.
For anyone else having this issue, here's what I did:
In node_modules/mongoose-mongodb-errors/lib/plugin.js on line 19, add a simple console.error(err.message) so you can actually get the output and not the regex handler error.
Because when you save an empty array of subdocuments in Mongoose it is equivalent to having the subschema set to values of null, this means that when Mongoose evaluates the indices of your subdocument collection it will evaluate it as having a value of null for each property. If you're indexing with a property (i.e. one of the properties in your subdocument schema has unique: true on it) then this is a violation as a null value cannot be unique, at least not in Mongo world. To get around this you can add sparse: true.
Any documents in the existing collection and the existing collection itself will create an issue with now having a changed index. You need to drop the index for this to work. I dropped the entire collection because I didn't need it anyways.
Here's my updated schema:
const surveyKeySchema = new Schema({
slug: {
type: String,
required: 'Please supply a slug',
unique: true,
lowercase: true,
sparse: true,
trim: true
},
name: {
type: String,
required: 'Please supply a name',
trim: true
},
responseCount: {
type: Number,
default: 0
}
})
I am trying to create an event list where users can add and remove themselves from events and specify if they are bringing guests with them to that event.
So I have an event schema and a user schema, where the event schema is referencing the user schema. So when a new event is created users can add themselves to that event with their ids.
Now I'm trying to make it so that users can also include guests. How Do I achieve that?
Here's an example
User Schema:
let UserSchema = new mongoose.Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
name:{
type: String,
require: true
},
password: {
type: String,
required: true
},
...
Event Schema:
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
// Guest property is ignored
attending: [{
type: mongoose.Schema.Types.ObjectId,
guest: Number, //This is being ingored and never updated
ref: 'User'
}]
})
Second way of defining the relavant part in the schema:
...
//In this example the guest will be added but duplicates will occur
user:[{
guest: Number, // To make it clear this is not referencing anything it's just a number
attending: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}]
How do I update the type and guest properties with addToSet (to prevent duplication) in the above configuration?
Event.findOneAndUpdate({_id:req.body.eventId}, query)
I don't think you understand how mongoose schemas work, you might want to spend some more time on their documentation.
What you have provided as code is what appears to be a field called Events in your Schema which is an array of objects, each object of which has a single field called attending, which itself is required to be an ObjectId type and reference the 'User' collection. There is also a guest property on the field definition which will be ignored by Mongoose as it doesn't understand what you're asking for.
Realize that what this data structure is, is instructions to Mongoose on how to validate and persist your data. It won't generally be updated at runtime for most applications and will not store data directly, again its purpose is to give clues to Mongoose as to how you want the data stored.
/** Edit based on comments and updated question **/
As I said before, you can't directly embed another field into the definition of a field. What you can do is create a mixed type which has both pieces of information, but that will require you to manage things yourself to some degree.
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
attendees: [{
user : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
guests : Number
}]
})
Anytime anyone is added to the attending list, you'll need to call event.markModified() to make sure it gets saved. If you don't want to allow duplicate users, you'll also need to check that. One way to make sure that happens is to populate() that field when you fetch the event, then just check locally for matches.
/** Edit #2 **/
You can also explicitly create another schema to 'hold' your user and # guests information, which will then create models that Mongoose will watch, and you can apply validation to them via normal Mongoose methods and not worry about dirty checking. That'd look like this:
// in ./models/attendee.js
let AttendeeSchema = new Schema({
user : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
unique : true
},
guests : Number
}
mongoose.model('Attendee', AttendeeSchema);
// in your Events definition
let Attendee = mongoose.model('Attendee');
let EventSchema = new mongoose.Schema({
date: {
type: Date,
unique: true,
timestamps: true,
required: true
},
title: {
type: String,
require: true
},
attendees: [Attendee]
})
/** Edit 3: Now, with queries **/
To insert a new attendee, given an existing event and a known user:
event.attendees.push(new Attendee({user: user, guests: 5}));
event.save(console.log);
To update an existing attendee, you'll need to find the one you're looking for first:
let attendee = event.attendees.find((attendee) => { return attendee._id.toString() === user._id.toString(); });
attendee.guests = 10;
event.save(console.log);
The title is pretty straight forward. I have an attribute which looks like this:
isSet: {
type: boolean,
defaultsTo: false
}
So my goal is to have the value set to false everytime a user is created. But when I do create a user this value is null/undefined
The only workaround I found is to set the values in the beforeCreate method
Type should be string. This should work:
isSet: {
type: 'boolean',
defaultsTo: false
}