I've Googled around and can't find any solid information on how to ignore duplicate errors when using bulk insert.
Here's the code I'm currently using:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let batch = col.initializeUnorderedBulkOp()
ids.forEach(function(id) {
batch.insert({ userid: id, used: false, group: argv.groupID })
})
batch.execute(function(err, result) {
if(err) {
console.error(new Error(err))
db.close()
}
// Do some work
db.close()
})
})
Is it possible? I've tried adding {continueOnError: true, safe: true} to bulk.insert(...) but that didn't work.
Any ideas?
An alternative is to use bulk.find().upsert().replaceOne() instead:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let batch = col.initializeUnorderedBulkOp()
ids.forEach(function(id) {
batch.find({ userid: id }).upsert().replaceOne({
userid: id,
used: false,
group: argv.groupID
});
});
batch.execute(function(err, result) {
if(err) {
console.error(new Error(err))
db.close()
}
// Do some work
db.close()
});
});
With the above, if a document matches the query { userid: id } it will be replaced with the new document, otherwise it will be created hence there are No duplicate key errors thrown.
For MongoDB server versions 3.2+, use bulkWrite as:
MongoClient.connect(mongoURL, function(err, db) {
if(err) console.err(err)
let col = db.collection('user_ids')
let ops = []
let counter = 0
ids.forEach(function(id) {
ops.push({
"replaceOne": {
"filter": { "userid": id },
"replacement": {
userid: id,
used: false,
group: argv.groupID
},
"upsert": true
}
})
counter++
if (counter % 500 === 0) {
col.bulkWrite(ops, function(err, r) {
// do something with result
db.close()
})
ops = []
}
})
if (counter % 500 !== 0) {
col.bulkWrite(ops, function(err, r) {
// do something with result
db.close()
}
}
})
Related
var query = { "to": req.params.id };
var mysort = { receivedDate: 1 };
Message.find(query, (err, doc) => {
if (!err) {
res.json(doc);
} else {
res.json(err);
}
});
The syntax is like the following:
db.collecttionName.find().sort({date:1});
But instead of date, you can pass in other criteria.
I have this code:
MongoClient.connect(config.mongoURL, {useNewUrlParser: true}, (err, db)=> {
if (err) {
console.log("Err", err)
cb(-1)
}
else {
var con = db.db('englishAcademy')
try {
con.collection("sound").updateOne({"_id": new ObjectID(sndId)}, {
$set: {
"snd_title": info.snd_title,
"snd_type": info.snd_type,
"snd_url": info.snd_url,
"snd_lsnId": info.snd_lsnId,
"snd_lvlId": info.snd_lvlId,
"snd_order": info.snd_order
}
}), (err, doc) => {
console.log("result")
if (err) {
console.log(err)
cb(-1)
}
else {
console.log(doc)
let result = 'row affected'
cb(doc)
}
}
}
catch (e) {
console.log(e)
}
}
})
could anyone please tell me what is wrong with my code?the updateOne function does not return anything.but my mongo database gets updated.
EDIT :
I have done this so far and it did not worked.could anyone please help?I used assert no success.I used new :true, no success.I used finde and update ,no success
let infor = {
"adm_name": info.adm_name,
"adm_username": info.adm_username,
"adm_password": info.adm_password
}
con.collection("admins").findOneAndUpdate({"_id": new ObjectID(admId)}, {
$set: infor
},{new:true} ), (err , result) => {
console.log("result")
if (err) {
console.log(err)
assert.equal(err, null);
cb(-1)
}
else {
let result = 'row affected'
assert.equal(1, result.result.n);
}
set new: true
MongoClient.connect(config.mongoURL, {useNewUrlParser: true}, (err, db)=> {
if (err) {
console.log("Err", err)
cb(-1)
}
else {
var con = db.db('englishAcademy')
try {
con.collection("sound").updateOne({"_id": new ObjectID(sndId)}, {
$set: {
"snd_title": info.snd_title,
"snd_type": info.snd_type,
"snd_url": info.snd_url,
"snd_lsnId": info.snd_lsnId,
"snd_lvlId": info.snd_lvlId,
"snd_order": info.snd_order
},{new: true}
}), (err, doc) => {
console.log("result")
if (err) {
console.log(err)
cb(-1)
}
else {
console.log(doc)
let result = 'row affected'
cb(doc)
}
}
}
catch (e) {
console.log(e)
}
}
})
Try this way ..
collection.findOneAndUpdate(
{"_id": new ObjectID(sndId)},
$set: yourData },
{ new: true },
function (err, documents) {
res.send({ error: err, result: documents });
}
);
Now you can return newData in cb.
I want to increment id's automatically in the mongoDB while posting the data. I am able to attach date for the req.body. How to attach ids with auto incrementation?
This is my post call:
router.post('/addVisualization', function (req, res, next) {
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db(dbName);
req.body.dateOfEntry = new Date();
function getNextSequence(id) {
var ret = db.counters.findAndModify(
{
query: { _id: id },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
dbo.collection("visualization").insertOne(req.body, function (err, resDB) {
if (err) {
throw err;
res.status(401);
res.send({
"status": 401,
"message": "Some error happened"
});
}
else {
console.log("1 document inserted");
res.status(201)
res.send({
"body": req.body,
"status": 201,
"message": "visualization has been added"
});
}
});
db.close();
});
});
Try out the below code to auto increment id's in mongoDB.
router.post('/addVisualization', function (req, res, next) {
MongoClient.connect(url, {
useNewUrlParser: true
}, function (err, db) {
if (err) throw err;
var dbo = db.db(dbName);
req.body.dateOfEntry = new Date();
req.body.isDeleted = "false";
var countRow;
var sequenceDocument = dbo.collection("counterVisualization").findOneAndUpdate({
_id: "tid"
}, {
$inc: {
sequence_value: 1
}
}, {
new: true
});
dbo.collection("counterVisualization").find({
_id: "tid"
}).toArray(function (err, result1) {
if (err) {
throw err;
} else {
countRow = result1[0].sequence_value;
req.body["_id"] = countRow;
dbo.collection("visualization").insertOne(req.body, function (err, resDB) {
if (err) {
throw err;
res.status(401);
res.send({
"status": 401,
"message": "Some error happened"
});
} else {
console.log("1 document inserted");
res.status(201)
res.send({
"body": req.body,
"status": 201,
"message": "visualization has been added"
});
}
});
}
});
});
});
In mongo db you don't have a auto increment ids as mysql or oracle, Please take a look at this tutorial for how to do it out of the box.
Use a separate counters collection to track the last id of the sequence.
db.counters.insert(
{
_id: "userid",
seq: 0
}
)
db.counters.insert(
{
_id: "productid",
seq: 0
}
)
Create a getNextSequence function that accepts a name of the sequence.
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true,
upsert : true // Creates a new document if no documents match the query
}
);
return ret.seq;
}
Use this getNextSequence() function during insert.
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Mr. X",
// ... more fields
}
)
db.products.insert(
{
_id: getNextSequence("productid"),
name: "Mr. Y",
// ... more fields
}
)
I have this function to findOneAndUpdate, it will find if the username if it exist then set the time field and increase number of other field.
function _lockIfFailedAttemptsReachLimit(username,next) {
colUser.findOneAndUpdate({ username }, { // increase failed attempt counter
$set: { failedLoginAt: new Date() },
$inc: { nFailedLogin: 1 },
}, { upsert: false, returnOriginal: false }, (err, result) => {
if (err) { // Undefined.
next('Undefined error!');
} else {
let foundUser = result.value;
if (_.isNil(foundUser)) { // cannot find username
//nothing here yet.
}
let nFailed = _.get(foundUser, 'nFailedLogin', 0);
let errMsg = `Invalid username or passsword. You have tried ${nFailed}/${MAX_FAILED_LOGIN_ATTEMPTS} login attempts`;
if (nFailed < MAX_FAILED_LOGIN_ATTEMPTS) {
next(errMsg);
} else {
_lockAccount(username, (err, result) => {
if (!err) {
errMsg += `. Your account has been locked for ${WAITING_TIME_AFTER_LOCKED} seconds.`;
}
next(errMsg);
});
}
}
});
}
Now I want in the same function if cannot find username, then it will insert username value and do the same process for that username. How could I do that in most effective coding ?
I tried:
function _lockIfFailedAttemptsReachLimit(username, req, res, next) {
colUser.findOneAndUpdate({ username }, { // increase failed attempt counter
$set: { failedLoginAt: new Date() },
$inc: { nFailedLogin: 1 },
}, { upsert: false, returnOriginal: false }, (err, result) => {
if (err) { // Undefined.
next('Undefined error!');
} else {
let foundUser = result.value;
if (_.isNil(foundUser)) { // cannot find username
//I think can try to put the code here ?
let username = (req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress).split(",")[0];
// insert username to the table and call the function to continue from the beginning
}
let nFailed = _.get(foundUser, 'nFailedLogin', 0);
let errMsg = `Invalid username or passsword. You have tried ${nFailed}/${MAX_FAILED_LOGIN_ATTEMPTS} login attempts`;
if (nFailed < MAX_FAILED_LOGIN_ATTEMPTS) {
next(errMsg);
} else {
_lockAccount(username, (err, result) => {
if (!err) {
errMsg += `. Your account has been locked for ${WAITING_TIME_AFTER_LOCKED} seconds.`;
}
next(errMsg);
});
}
}
});
}
Been banging my head in the wall on this, so any help would be greatly appreciated. With MongooseJS, I'm doing a Model.find and then looping through those results and doing a findAndUpdate.
(basically, get list of URLS from MongooseJS, "ping" each URL to get a status, then update the DB with the status).
Schema
var serverSchema = new Schema({
github_id: { type: String, required: true },
url: { type: String, required: true },
check_interval: Number,
last_check: {
response_code: Number,
message: String,
time: Date
},
created_at: Date,
updated_at: Date
})
Here's a code snippet:
// Doesn't work
Server.find(function (err, items) {
if (err) return console.log(err)
items.forEach(function (item) {
var query = {url: item.url}
Server.findOneAndUpdate(query, {updated_at: Date.now()}, function (err, doc) {
if (err) return console.log(err)
console.log(doc)
})
})
})
// Works!
var query = {url: 'https://google.com'}
Server.findOneAndUpdate(query, {updated_at: Date.now()}, function (err, doc) {
if (err) return console.log(err)
console.log(doc)
})
With debugging on, I can see that the .find() is getting the data I want. However, it seems that he findOneAndUpdate within the .find() never runs (item.url is set correctly) and I don't get any errors, it just doesn't run.
Any help would be GREATLY appreciated.
You can achieve that without find and then update you can do this in only one update operation
Server.update({}, { $set: { updated_at: Date.now() } }, function(err, doc) {
if (err) return console.log(err) {
console.log(doc)
}
})
In case you need to loop on items for specific reason to handle urls then try the code below
var Server = require('../models/server');
Server.find(function(err, items) {
if (err) {
return console.log(err)
} else {
items.forEach(function(item) {
var query = { url: item.url }
Server.update(query, { $set: { updated_at: Date.now() } }, function(err, doc) {
if (err) return console.log(err)
console.log(doc)
})
})
}
})
Mongodb Connection:
var secrets = require('./secrets');
var mongoose = require('mongoose');
module.exports = function() {
var connect = function() {
var mongoLink = "";
if (process.env.NODE_ENV === 'production') {
mongoLink = secrets.db.prod;
} else {
mongoLink = secrets.db.dev;
}
mongoose.connect(mongoLink, function(err, res) {
if (err) {
console.log('Error connecting to: ' + mongoLink + '. ' + err);
} else {
console.log('Connected to: ' + mongoLink);
}
});
};
connect();
mongoose.connection.on('error', console.log);
mongoose.connection.on('disconnected', connect);
}