How to save same document in MongoDB? - node.js

My Schema
const mongoose = require('mongoose');
const test_schema = new mongoose.Schema({
Name: {
type: String
}
});
const chatting = mongoose.model('chat', test_schema);
module.exports = chatting;
Getting model of above give the schema
const chat = require('./models/chatting.js');
Save Variables
const one = new chat({
Name : "John"
})
const two = new chat({
Name : "John"
})
Now Saving
await chat.insertMany([one, two])
but i got duplicate name key error

You provided a wrong schema to us. (test_schema != chatting_schema). check your chatting schema and see if it is structured somewhat like this:
const chatting_schema = new mongoose.Schema({
Name: {
type: String
unique: true
}
});
if so, remove the unique property.
also, when you already created a document you can just use the .save() function like
await one.save();

Related

Auto-generate employee ID using mongoose and nodejs

I'm working on a web app project using MEAN stack technology. I want to generate 'empId' (employee ID) automatically when a request to add a new employee is received. How can I do the same and store the generated 'empId' in the same document where I keep employee details?
Thanks in advance!
Unless there are other requirements that haven't been stated, you can simply generate empId when handling the request to add a new employee, and include it with other properties that may be supplied by the caller:
const schema = new Schema({ name: String, empId: String });
const Employee = model('Employee', schema);
// then when handling an "add employee" request:
const { name } = req.body; // properties from request
const empId = generateEmployeeId(); // e.g., "uuid()"
const employee = new Model({name, empId})
You can also automatically include an empId with each new Document by supplying it as a default in the mongoose Schema. Combine that with a library like nanoid (that gives you a bit more control over the ids generated) and you would have something like:
const schema = new Schema({
name: String,
empId: {
type: String,
default: () => nanoid()
}
})
Also keep in mind that mongodb will always create a unique identifier for each document in the _id property.
I solved the code using nanoid and presave feature of mongoose.
The code below generates a user friendly id that can be used for many different utilities.
The only potential issue is if the loop keeps finding same id due to the huge amount of users in db(this should not be an issue most apps), this issue can be reduced by either increasing the size of custom alphabets or by just adding more custom characters.
import mongoose from 'mongoose'
import { customAlphabet } from 'nanoid/async'
const schema = new mongoose.Schema({ name: String, empId: String });
const Employee = mongoose.model('Employee', schema);
employeeSchema.pre('save', async function (next) {
if (this.isNew) {
const nanoid = customAlphabet('1234567890abcdefABCDEF', 10)
let unique = true
let id = ''
while (unique) {
id = await nanoid()
const user = await Employee.findOne({ empId: id })
if (!user) {
unique = false
}
}
this.empId = id
}
next()
})

How do I update the existing documents' schema?

I'm using mongoose to do some MongoDB operations.
At the beginning the category was number,
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const sampleSchema = new Schema({
category: {
type: Number,
}
})
module.exports = mongoose.model("SampleSchema", sampleSchema);
Now the category changed to String, So I changed the model like this
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const sampleSchema = new Schema({
category: {
type: String,
}
})
module.exports = mongoose.model("SampleSchema", sampleSchema);
The problem is, I have already inserted 200 records into this collection. Is there any way to update the category value with a string and change its type to string?
Please get All data by query and update it one by one in loop.
Like:
db.tableName.find( { 'status' : { $type : 1 } } ).forEach( function (val) {
val.status = new String(val.status);
db.tableName.save(val);
});
I changed the category to mixed, that's working fine with numbers and string.
Thanks for the help #prasad_

Multiple schema in a file not working

I have two schema in singel schema.js file
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var Organizationn = new mongoose.Schema({
name: String,
add: String,
name:String
});
module.exports = {
user: user,
Organizationn: Organizationn
};
accessing it like
var models = require("../models/schema");
models.user.findOne()
it says findone is not a function
whereas If i use singel user in a file it is working.
I have gone through this link and did export like above
cant get data from database after multiple schema declared (mongoose + express + mongodb
but not working
any idea?
Thanks
With the help of #anthony I figure out the issue
I need to do the below
module.exports = {
user: mongoose.model('user', user),,
Organizationn: mongoose.model('Organizationn', Organizationn)
};
If you exports more than one file than you will have to import with curly braces { schema1 }
var mongoose = require('mongoose');
var user = new mongoose.Schema({
name: String,
add: String,
role: String
});
var organization = new mongoose.Schema({
name: String,
add: String,
name:String
});
const userSchema = mongoose.model('users', user),
const organizationSchema = mongoose.model('organizations', organization)
module.exports = { User: userSchema, Organization: organizationSchema }
and then import
var { User } = require("../models/schema");
var { Organization } = require("../models/schema");
User.findOne()
Organization.findOne()
Try to look at it in this abstract way:
A mongoose.Schema is basically just an object.
A mongoose.model is a class that you customize with your schema object.
In other words, mongoose.model has all the database functions attached to it, the schema by itself doesn't.

how can I ref a model that is in another folder?

for example the nexts schemas are in diferent folders like these:
cr/user
lms/content
this is the schemaContent
user: {
type: Schema.Types.ObjectId,
ref: 'cr/user'
}
How can I ref user from Content?
because when I used cr/user I get an error "Schema hasn't been registered for model"
I need just populate user from content like Content.find().populate({ path: 'users' }) Keeping user in the folder called cr and content in the folder called lms
You are trying to nest documents. Try below approach to nest document.
i will assume the directories cr and lms are inside the directory called demoproject
demoproject/cr/user.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name:{
type : String,
required: true
}
});
const User = mongoose.model("User",UserSchema);
module.exports = User;
demoproject/lms/content.js
./../cr/user - go back from lms directory and get into cr/user
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const User = require("./../cr/user");
const ContentSchema = new Schema({
type:{
type : String,
required: true
},
users : [{
type : Schema.Types.ObjectId,
ref : "User"
}]
});
const Content = mongoose.model("Content",ContentSchema);
module.exports = Content;
How can I ref user from Content?
i hope your question is clear now. Keep reading below
Moment of truth
Lets insert data by using these two models.
Create a file to write mongo queries (demoproject/index.js).
As User model is nested into Content model, we need to first save data into User model
Then save data into Content model
Now push data into users object present in Content Model contentdata.users.push(userdata);
Donot forget to save the contentdata after pushing the userdata object into contentdata contentdata.save();
demoproject/index.js
const User = require("./cr/user");
const Content = require("./lms/content");
const userobj = new User({name : "rockyjohnson"});
const contentobj = new Content({type : "gloves"});
userobj.save().then((userdata)=>{
contentobj.save().then((contentdata)=>{
contentdata.users.push(userdata);
contentdata.save();
}).catch((err)=>{
console.log("err while saving contentdata ", err);
})
}).catch((err)=>{
console.log("err while saving userdata ", err);
})
Mongodb output
That is all
Update: answer for the second question
find returns an array object in its promise. i'm able to extract users object present inside Content model here. Below is the query i used to verify
Content.find().then((data)=>{
data.forEach(element => {
console.log("element users ",element.users); // element.users contains all id's stored in the users array
});
}).catch((err)=>{
console.log("err ",err);
})

How to set ObjectId as a data type in mongoose

Using node.js, mongodb on mongoHQ and mongoose. I'm setting a schema for Categories. I would like to use the document ObjectId as my categoryId.
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
categoryId : ObjectId,
title : String,
sortIndex : String
});
I then run
var Category = mongoose.model('Schema_Category');
var category = new Category();
category.title = "Bicycles";
category.sortIndex = "3";
category.save(function(err) {
if (err) { throw err; }
console.log('saved');
mongoose.disconnect();
});
Notice that I don't provide a value for categoryId. I assumed mongoose will use the schema to generate it but the document has the usual "_id" and not "categoryId". What am I doing wrong?
Unlike traditional RBDMs, mongoDB doesn't allow you to define any random field as the primary key, the _id field MUST exist for all standard documents.
For this reason, it doesn't make sense to create a separate uuid field.
In mongoose, the ObjectId type is used not to create a new uuid, rather it is mostly used to reference other documents.
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Product = new Schema({
categoryId : ObjectId, // a product references a category _id with type ObjectId
title : String,
price : Number
});
As you can see, it wouldn't make much sense to populate categoryId with a ObjectId.
However, if you do want a nicely named uuid field, mongoose provides virtual properties that allow you to proxy (reference) a field.
Check it out:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
title : String,
sortIndex : String
});
Schema_Category.virtual('categoryId').get(function() {
return this._id;
});
So now, whenever you call category.categoryId, mongoose just returns the _id instead.
You can also create a "set" method so that you can set virtual properties, check out this link
for more info
I was looking for a different answer for the question title, so maybe other people will be too.
To set type as an ObjectId (so you may reference author as the author of book, for example), you may do like:
const Book = mongoose.model('Book', {
author: {
type: mongoose.Schema.Types.ObjectId, // here you set the author ID
// from the Author colection,
// so you can reference it
required: true
},
title: {
type: String,
required: true
}
});
My solution on using ObjectId
// usermodel.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
UserSchema.set('autoIndex', true)
module.exports = mongoose.model('User', UserSchema)
Using mongoose's populate method
// controller.js
const mongoose = require('mongoose')
const User = require('./usermodel.js')
let query = User.findOne({ name: "Person" })
query.exec((err, user) => {
if (err) {
console.log(err)
}
user.events = events
// user.events is now an array of events
})
The solution provided by #dex worked for me. But I want to add something else that also worked for me: Use
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
if what you want to create is an Array reference. But if what you want is an Object reference, which is what I think you might be looking for anyway, remove the brackets from the value prop, like this:
let UserSchema = new Schema({
username: {
type: String
},
events: {
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}
})
Look at the 2 snippets well. In the second case, the value prop of key events does not have brackets over the object def.
You can directly define the ObjectId
var Schema = new mongoose.Schema({
categoryId : mongoose.Schema.Types.ObjectId,
title : String,
sortIndex : String
})
Note: You need to import the mongoose module
Another possible way is to transform your _id to something you like.
Here's an example with a Page-Document that I implemented for a project:
interface PageAttrs {
label: string
// ...
}
const pageSchema = new mongoose.Schema<PageDoc>(
{
label: {
type: String,
required: true
}
// ...
},
{
toJSON: {
transform(doc, ret) {
// modify ret directly
ret.id = ret._id
delete ret._id
}
}
}
)
pageSchema.statics.build = (attrs: PageAttrs) => {
return new Page({
label: attrs.label,
// ...
})
}
const Page = mongoose.model<PageDoc, PageModel>('Page', pageSchema)
Now you can directly access the property 'id', e.g. in a unit test like so:
it('implements optimistic concurrency', async () => {
const page = Page.build({
label: 'Root Page'
// ...
})
await page.save()
const firstInstance = await Page.findById(page.id)
const secondInstance = await Page.findById(page.id)
firstInstance!.set({ label: 'Main Page' })
secondInstance!.set({ label: 'Home Page' })
await firstInstance!.save()
try {
await secondInstance!.save()
} catch (err) {
console.error('Error:', err)
return
}
throw new Error('Should not reach this point')
})

Resources