Mongoose variable key name - node.js

I have a mongo object and wish to access it via mongoose for my web app. The schema I've defined has an Object storing user ids and a 3-level value (yes, maybe or no).
e.g.
"user_info": {
"<id_value_1>": "y",
"<id_value_2>": "n"
}
The id_value_*s above are the users session ids so a long string of random characters. How can I create a mongoose Schema for this?
Would user_info: {String, String} work?
I could restructure it so that the user_info is an array of objects { "sessionid": "<value>", "value: "y"}, which would be ok, is this the best option?

You'll be better off if you avoid dynamic keys in your schema and go with your second idea of:
user_info: [{sessionid: String, value: String}]
You can use the $ positional operator to update individual user_info array elements by sessionid.

You may try with Schema Type Mixed like this way
var user = new Schema({
info: [Schema.Types.Mixed]
});
user.info = { any: { thing: 'i want' } };
user.markModified('info');
You can read more about it here

After testing the above, I found that defining the schema as user_info: { String: String } is a valid way to do this (option 1 specified in the question).

You may define objects and arrays in your schema. You may even combine them. For example, this is an array of objects:
var user = new Schema({
foo: [ {
address: {type: String},
email: {type: String, unique: true}
}],
bar: [ "simple", "array" ]
});

Related

How to insert Array of objects in mongoDB?

I am very new to MONGO DB so please bear with me.I am having a problem my array of objects is not working properly .
Here is my schema
const playerSchema = new mongoose.Schema({
name: String,
stats :{
wins:Number,
losses:Number,
xp:Number
},
achievement:[
{
name:String,
date: String
}
] });
Here is my document
const fluffy = new playerModel({
"name":"nic raboy",
"stats":{
"wins":5,
"losses":10,
"xp":300
},
"achievements":[
{"name":"Massive XP","date" :"25-08-21"},
{"name":"instant loss","date":"24-08-21"}
]
});
however in mongodb atlas its only showing array...and i cant see the objects inside...
SCREENSHOT
Your schema is correct, it seems your input is wrong,
In schema definition you named it achievement, whereas in input document it is achievements. Correct this everything will work as you expected.
Explanation
The schema is expecting achievement and you inserted achievements, that is why it is shown as an empty array in the database. To avoids this kind of typos in the future, use the required flag.
const playerSchema = new mongoose.Schema({
name: String,
stats: {
wins: Number,
losses: Number,
xp: Number
},
achievements: [
{
name: {
type: String,
required : true,
},
date: {
type: String,
required : true, // required informs for missing fields
}
}
]
})
Refer this link for more on validation
You can use insertMany see the doc here.
Of course, a while loop should work find calling multiple times insertOne, though I advise you to use the insertMany() method.
If you're new to MongoDB, I strongly encourage you to have a look at MongoDB University's MongoDB basics course as well as the MongoDB for JavaScript Developers course.

How to use $push inside $set in mongoose?

I'm using express-restify-mongoose library to have rest endpoints agaist mongoose.
I have schema looks like this:
const BookSchema = new Schema(
{
name: { type: String },
items: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }],
}
);
So I send http patch request: { name: 'blabla' } and it change the name as expect.
But when I want to add item to items array like { items: ["5dd138199f6ecb3990360328"] } its replace the entire object (with one 5dd138199f6ecb399036032d item).
After I digging in the source code I see here the function uses findOneAndUpdate and $set.
So my question is there is any way to use $push or any function/property in the $set value?
I can't add to this library, but maybe there is any workaround solution here?
I think the closest solution in mongoose is to use Set Elements in Arrays:
"items.1": "5dd138199f6ecb3990360355"
Which will add to array, but you have to pass the position.

How would i make the mongoose Schema dynamically according to the other fields value in node.js?

i want to define the schema dynamically according to the condition using mongoose
Schema
new mongoose.Schema({
type: String, //BASIC OR ADVANCE
// only for type = BASIC
name: String,
age: Number
/*
want these fields too but only if type = ADVANCE
email: String,
password: Number
PhoneNumber: String
*/
});
how would i achieve this kind of schema using mongoose.
it depends on what your approach to your database is. you can simply create two types with identifiers as Advance and Basic and use middleware to maintain the flow. Now to answer your question:
something like:
new mongoose.Schema({
type: String, //BASIC OR ADVANCE
// only for type = BASIC
name: String,
age: Number,
advance: []
And now you can check if advance is empty or not. Seriously it all depends on your approach, how you deal with the problem. Once a Schema is declared you can without the advance field, you can still save data like:
const MyModel = mongoose.model('Test', new Schema({ name: String }));
const doc = new MyModel();
doc.advance = {
email: "test#test.com",
password: 1234,
PhoneNumber: 1234
}
doc.save();
But with this structure if you want to know the Schema, you'll think that in your file it is only name and age and later when you start exploring, you'll find out that you are doing something like this and using a proper structure.
Think of moongoose documents as JavaScript Objects, there is a reason it is known as non-Structured data. Hope this explanation helps.

How to get enum values from mongoose schema using virtual method?

I'm having difficulty getting enum values from my Mongoose schema using a virtual method on that same schema.
The property I'm trying to access in the schema is defined as follows:
, roles: {
type: [{
type: String
, enum: ['user', 'admin']
}]
, default: ['user']
}
The following is my virtual method I'm using to grab the enum values:
// Returns an array of all possible role enum values
UserSchema.virtual('possibleRoles').get(function() {
return this.schema.path('roles').caster.enumValues;
});
This works, however other examples I found online went about it in a different way. An example of this is here: Access the list of valid values for an Enum field in a Mongoose.js Schema
Is my method for accessing enums on a property dirty or incorrect? Is there a cleaner way I could write this?
This is clean and easy way.
var possibleRoles = ['user', 'admin'];
var UserSchema = new Schema({
roles: {
type: [{type: String, enum: possibleRoles}],
default: ['user']
}
});
UserSchema.virtual('possibleRoles').get(function () {
return possibleRoles;
});
remove the caster part, i don't know why that is there:
return this.schema.path('roles').enumValues;
that should work without any other issues

How to fetch the old records from the mongo after the schema change

I have an existing schema like
exports.OldCollectionSchema= new Schema({
Id: { type: Schema.ObjectId },
parentId: { type: Schema.ObjectId },
userId: { type : String },
userName: { type : String })
Now, I waned to use the above collection in two scenarios by adding a new field type
type would be scenario a or scenario b
so I wanted to fetch the old records + type = "scenario a" and to show that in a page
How is it possible ?
I do believe Mongoose has a __v field denoting version however I am no Mongoose expert so I will just paste the easy hacky query that you can do:
db.col.find({type: {$exists: false, $in: ['a']}});
That will basically say: "Get all the records where they don't yet have a scenario (basically the ones before this schema) and combine them with the ones that have a type of 'a'"
Edit
Actually a better way is just to use null here:
db.col.find({type: {$in: ['a', null]}});

Resources