MongoDB and Nodejs insert ID with auto increment - node.js

I am new to NodeJs and MongoDB, i want to insert row with auto increment primary key 'id'. also defined a function called getNextSequence on mongo server.
this is working perfect on Mongodb server
> db.user.insert({
"id" : getNextSequence('user_id'),
"username" : "test",
"email" : "test#test.com",
"password" : "test123"
})
now i want to insert from NodeJs.I have tried this but not working
db.collection('user').insertOne({
id : "getNextSequence('user_id')",
username : query.name,
email: query.email,
password: query.pass
}, function(err, result) {
assert.equal(err, null);
console.log("row insterted ");
callback();
});

Assuming that getNextSequence is a server-script function (i.e. a method you defined and saved via db.system.js.save), it is not callable outside of the server. One way to go is to use eval, which forces the server to evaluate a string as a js code, even though it is not a good practice. Here is an example:
db.eval('getNextSequence(\'user_id\')', function(err, result) {
db.collection('users').insert({
"id" : result,
"username" : "test",
"email" : "test#test.com",
"password" : "test123"
});
});
Another way is to follow the mongo tutorial and to implement the getNextSequence directly in NodeJS. The syntax is pretty much the same:
function getNextSequence(db, name, callback) {
db.collection("counters").findAndModify( { _id: name }, null, { $inc: { seq: 1 } }, function(err, result){
if(err) callback(err, result);
callback(err, result.value.seq);
} );
}
You then use it in your nodeJS code like:
getNextSequence(db, "user_id", function(err, result){
if(!err){
db.collection('users').insert({
"_id": result,
// ...
});
}
});
Note: of course, you need to have set the counters collection as explained in the docs.

You can also use "mongoose-auto-increment".
The code has just 4 lines
var mongoose = require('mongoose');
var autoIncrement = require('mongoose-auto-increment');
autoIncrement.initialize(mongoose.connection);
userSchema.plugin(autoIncrement.plugin, 'user');
example :
npm i mongoose-auto-increment
connections.js :
const mongoose = require('mongoose');
require("dotenv").config;
const uri = process.env.MONGOURL;
mongoose.connect(uri, { useNewUrlParser: true }, (err) => {
if (!err) { console.log('MongoDB Connection Succeeded.') }
else { console.log('Error in DB connection : ' + err) }
});
require('../schema/userSchema');
userSchema.js :
var mongoose = require('mongoose'); // 1. require mongoose
var autoIncrement = require('mongoose-auto-increment'); // 2. require mongoose-auto-increment
var userSchema = new mongoose.Schema({
name: { type: String },
password: { type: String },
email: { type: String, unique: true, required: 'This field is required.' },
});
autoIncrement.initialize(mongoose.connection); // 3. initialize autoIncrement
userSchema.plugin(autoIncrement.plugin, 'user'); // 4. use autoIncrement
mongoose.model('user', userSchema);

To accomplish this, we will create a function that will keep trying to save the document untill it will have been saved with incremented _id
async function retryUntilSave(db, task) {
try {
const index = await db.collection('tasks').find().count() + 1;
const result = await db.collection('tasks').insertOne(Object.assign(task, { _id: index }))
} catch (error) {
if (error.message.includes("_id_ dup key")) {
console.log("ID already exists!")
console.log("Retrying...");
retryUntilSave(db, task)
} else {
console.log(error.message);
}
}
}
We can use task._id: index instead of Object.assign()
finally you can test this by making some concurrent requests
for (let index = 0; index < 20; index++) {
setTimeout(async () => {
await retryUntilSave(db, { title: "Some Task" })
}, 1000);
}
This function will handle easily if two or more tasks submitted at the same time because mogod throws error when we try to insert a document with duplicate _id, then we will retry saving the document again with incremented _id and this process will run until we save the document successfully !

You can also use "mongodb-autoincrement" module of node js. For example:
var autoIncrement = require("mongodb-autoincrement");
exports.yourMethod = function(newData, callback) {
autoIncrement.getNextSequence(db, your-collection-name, function (err, autoIndex) {
newData.id = autoIndex;
//save your code with this autogenerated id
});
}

You can use the below package on a model schema to auto-increment your collection field.
mongoose-auto-increment //you can download it from npm
Here I am not focusing on how to connect MongoDB. I just focus on how you can integrate auto increment in your model/collection/table.
const mongoose = require("mongoose"); //
const autoIncrement = require("mongoose-auto-increment");
const post_schema = new mongoose.Schema({
title: {
type: String,
required: true,
min: 3,
max: 225,
},
slug: {
type: String,
required: true,
},
});
autoIncrement.initialize(mongoose.connection);
post_schema.plugin(autoIncrement.plugin, {
model: "post", // collection or table name in which you want to apply auto increment
field: "_id", // field of model which you want to auto increment
startAt: 1, // start your auto increment value from 1
incrementBy: 1, // incremented by 1
});
module.exports = mongoose.model("post", post_schema);

Related

Get the _id of the sub-document from mongoose findOne query

The schema of my Sample model is:-
var nameSchema = new mongoose.Schema({
firstname:String,
lastname:String
})
var sampleSchema= new mongoose.Schema({
number: {
type: String
},
name :{
type : [nameSchema]
}
});
I am trying to update the first and last name by searching them by their number property by making use of Sample.findOne({number:number}). And i am performing the update operation in the following manner:-
module.exports.updateNumber = function(req, res){
var number= req.body.number;
var lname= req.body.lname;
var fname= req.body.fname;
Sample
.findOne({number:number})
.select('name')
.exec(function(err, doc){
console.log(doc)
var this_id;
var thisService = doc.name.id('this_id');
thisService.firstname=fname;
thisService.lastname=lname;
doc.save(function(err, update) {
if (err) {
res
.status(500)
.json(err);
} else {
res
res.render('done')
}
});
})
}
If i console log the output i got is:
{ _id: 5bc5d71f47ff14361c0639d1,
name:
[ { _id: 5bc5d71f47ff14361c0639d2,
firstname: 'firstname',
lastname: 'lastname' } ] }
Is there any way, i could store _id: 5bc5d71f47ff14361c0639d2 in 'this_id' variable, so that this updation would be possible
name is an array, so if you want the first _id then name[0]._id would suffice, if you want an array of all values for _id in name, then name.map((person) => person._id) would give you an array of _id
However, more details about the context of this object would help give a better answer.

node.js mongoose subfield in a document

I have been working with node.js and mongoose for sometime and I am hitting a wall. I have a database with 20,000 documents and when i search the database from the cli it works fine.
db.Tickets.find({ "Customers.Customer.CustomerID" : '123123123' })
This returns 256 results
Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema for Ticket
var Ticket = new Schema({
UserName: {
type: String
},
Status: {
type: String
},
TicketNumber: {
type: Number
},
Name: {
type: String
},
Description: {
type: String
},
TicketTypeName: {
type: String
},
DueDate: {
type: Date
},
MapCollectDate : {
type: Date
},
NumberofUsersAffected : {
type: Number
},
DNNumber : {
type : String
},
RevisionDate : {
type : Date
},
CommercialImpact : {
type: String
},
Customers :[{
Customer: [{
CustomerID: Number,
CustomerName: String
}]
}],
Although if I test this in node.js using mongoose. I can't get it to return anything
I have a generic search that works
Ticket.find(function (err, tickets){
But can't get the specific search to work.
I am Connecting to Mongo
const config = require('./db');
//const Course = require('./models/Course');
//const CourseRoute = require('./routes/CourseRoute');
const Ticket = require('./models/Ticket');
const TicketRoute = require('./routes/TicketRoute');
const PORT = 4000;
mongoose.connect(config.DB).then(
() => {console.log('Connected to MongoDB') },
err => { console.log('Error connecting to MongoDB' +err)
});
Output of the log
Your node js server is running on PORT: 4000
Connected to MongoDB
Connected to MySQL
My Route End point
router.route('/').get(function (req, res) {
Ticket.find({ "Customers.Customer.CustomerID" : global.auth_username }, function(err, ticket) {
if(err){
console.log(err);
}
else {
res.json(tickets);
}
});
});
Also tried without the variable
router.route('/').get(function (req, res) {
Ticket.find({ "Customers.Customer.CustomerID" : "123123123" }, function(err, ticket) {
if(err){
console.log(err);
}
else {
res.json(tickets);
}
});
});
I had the same issue when I forgot to connect to Mongoose before running query
mongoose.connect(MONGO_URL, mongoOptions)
.then(() => {
// do your thing here
})
You had over a year to figured this out, and I am sure that you did so, but either way it seems that you have a typo in your code. The callback parameter is named ticket - function(err, ticket) {, whereas you are logging tickets - res.json(tickets);. In the generic test you correctly wrote tickets - Ticket.find(function (err, tickets){, which is probably why it worked.
The takeaway lesson here is - use debugging tools instead of logging, makes it easier to catch such problems.
Also, it would be appropriate to answer your own question once you've figured it out. But given that this is probably completely useless, you might as well delete it. Cheers!

insert and insertOne not a function and update not creating mongo ID

I thought I could read my way to this solution, but I cant see what im doing wrong.
Here is my model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var inspectSchema = new Schema({
_id: Object, // Mongo ID
property: String, // Property ID
room: String, // The room Name
item: Array // The Items text
});
module.exports = mongoose.model('inspectModel', inspectSchema, 'inspect');
And here is where I try to insert or insertOne
var inspectModel = require('../../models/inspectModel');
var inspectTable = mongoose.model('inspectModel');
inspectTable.insert(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
},
function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
})
I tried
inspectTable.insert
inspectModel.insert
inspectTable.insertOne
inspectModel.insertOne
No matter what I always get
TypeError: inspectTable.insert is not a function
I also tried just update with { upsert: true } but then the mongo ID becomes null.
Any ideas?
The method you're looking for is create:
inspectTable.create(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
}, ...
However, your schema definition of _id: Object is likely wrong. Just leave any definition of _id out of your schema and it will use the default ObjectId, which is likely what you want.
You can try this
var insert_table = new inspectTable(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
});
insert_table.save(function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
});

MongoDB and mongoose: how to add an object if it doesn't already exist

I am having some trouble with mongoDB/mongoose and node.js. I am used to SQL, and mongoDB is...hard! Here is my schema:
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
var itemSchema= mongoose.Schema({
item_info : {
user_id : Number,
location : String,
item_id : Number,
title : String
},
item_hist : {
user_id : Number,
location : String,
item_id : Number,
founddate : String
}
});
module.exports = mongoose.model('item', itemSchema);
And I can add a new item by doing this:
var item= require('./app/models/item');
var item= new item();
item.item_info.user_id = 12345;
item.item_info.location = 'This address';
item.item_info.item_id = 4444;
item.item_info.title = 'New item';
item.save(function(err)
{
if (err) throw err;
});
What I want to be able to do is say: "look for an item with item_info.item_id 5555. if it exists, do nothing. if it doesn't exist, then add it to the database." I've read through so much mongodb and mongoose documentation, but between using dot notation and accessing through nodejs instead of command line mongodb, I still can't figure out how to do this. SQL seemed so much easier!
Just use this -
var query = { user_id: 12345, location: "This address", item_id: 4444, title: "New item" },
options = { upsert: true };
Model.findOneAndUpdate(query.item_id, query, options, function(error, result) {
if (error) return;
// do something with the document
});

Mongoose saving for populate

I'm new to Mongoose and Nodejs developement in general and I've got a bit of confusion around how to properly set up saving my records. Here are my two schemas:
Download
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var downloadSchema = Schema({
title : String,
description : String,
_project : { type: Schema.Types.ObjectId, ref: 'Project' }
});
module.exports = mongoose.model('Download', downloadSchema);
Project
...
var projectSchema = Schema({
name : String,
url : String,
pwd : String,
_downloads : [{type: Schema.Types.ObjectId, ref: 'Download' }]
});
module.exports = mongoose.model('Project', projectSchema);
This appears to be working correctly. The documentation explains my use-case of saving a download and linking a project, but I'm not sure how to properly populate the Project._downloads. Here's what I've done:
Express route handler:
function createDownload(req, res) {
// the Project Id is passed in the req.body as ._project
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
var dload = new Download(dldata);
dload.save( function (err, download) {
project._downloads.push(download._id);
project.save( function(err){
var msg = {};
if(err) {
msg.status = 'error';
msg.text = err;
}else {
msg.status = 'success';
msg.text = 'Download created successfully!';
}
res.json(msg);
});
});
});
}
This seems overcomplicated to me. Am I supposed to be manually pushing to the ._downloads array, or is that something Mongoose is supposed to handle internally based on the schema? Is there a better way to achieve it so that I can do:
Download.find().populate('_project').exec( ...
as well as:
Project.findOne({_id : _projectId}).populate('_downloads').exec( ...
According to the mongoose docs there are 2 ways to add subdocs to the parent object:
1) by using the push() method
2) by using the create() method
So I think that your code can be a bit simplified by eliminating the operation of saving a new Download item:
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.push(dldata);
project.save(function(err) {
// handle the result
});
});
}
or
function createDownload(req, res) {
var dldata = req.body;
Project.findOne({ _id : dldata._project }, function(err, project) {
// handle error
project._downloads.create(dldata);
project.save(function(err) {
// handle the result
});
});
}

Resources