Node.js mongodb bulk insert - javascript

i'm kinda new to node.js and mongo and i'm having a little problem. I can't bulk insert documents into mongodb using ajax on client and nodejs/express on server. Here is my client code:
<button class="btn>Send</button>
data = {'test':'test1','test':'2','test':'test1','test':'test2','test':'test1','test':'test2'}
$(".btn").click(function(){
$.ajax({
url: 'http://localhost:8000/2',
type: 'post',
dataType: 'json',
data: data
});
});
And here is my route handler in node:
app.post('/2', function(req, res){
var docs = [];
for(var i = 0; i < 10000; i++) {
docs[i] = req.body;
}
db.collection('test', function(err, collection){
collection.insert(docs, function(err, result) {
if (!err) {
console.log(result);
res.end();
} else {
throw err
}
})
});
})
I'm getting data nicely with console.log(docs), but my test collection is empty. What am i missing? Thanks

app.post('/2', function(req, res){
var docs = req.body.data; // ur json data is now in node end
var i=0;
var bulk = test.collection.initializeUnorderedBulkOp(); // test is the model name. I used mongoose
// now using loop insert all json data inside bulk variable
for (i = 0; i < docs.length; i += 1) {
bulk.insert(docs[i]);
}
//after insertion finished u might need node-async module, to insert first
//then asynchronously execute bulk
bulk.execute(function (errx) {
if (errx) { return next(errx); }
console.log('Success');
});
})
you need to define test schema and test model correctly.
For further details you can read following links
https://docs.mongodb.com/manual/reference/method/Bulk.insert/

You can try mongoose variant. It is a bit more comfy and have some benefits.
const mongoose = require('mongoose');
app.post('/2', function(req, res){
var docs = req.body.data;
const Entity = mongoose.model('test', new Schema({}, {strict: false}));
Entity.insertMany(docs).then(x => res.send(x)).catch(e => res.send(e));
}
You can also define mongoose schema and change strict to true to have db validation.
new Schema({
foo: String,
bar: Number
}, {strict: true})

Related

Node JS : use mongodb on imported module

I have a app.js that connect to a mongodb database an display it with express.My app.js is starting to be quite long. So I'm trying to do "modular design". I need to do a "timer.js" that will do some stuff in my mongodb with a timer.
I want to import this function from "checking.js" but this file require mongodb, some constant from DOTENV etc. so I need a import/export relation between them. How to do it ?
App.js (main file)
require('dotenv').config()
const POWER = process.env.POWER;
var mongoDb = require('mongodb');
var mongoClient = mongoDb.MongoClient;
const serverUrl = process.env.ENV_SERVEUR_MONGO_URL;
const useDB = process.env.ENV_MONGO_DATABASE;
app.get('/top', function (req, res) {
var resultArray = [];
mongoClient.connect(serverUrl, function (err, client) {
var db = client.db(useDB);
if (err) throw err;
var cursor = db.collection('top').find().sort({ _id: -1 });
cursor.forEach(function (doc, err) {
resultArray.push(doc);
}, function () {
client.close();
res.render('pages/top', { items: resultArray })
});
});
});
var checking = require('./checking')
Checking.js
function checkingdatabase() {
// ERROR require mongodb, variable undefined etc.
mongoClient.connect(serverUrl, function (err, client) {
var db = client.db(useDB);
if (err) throw err;
//do stuff
});
}
setInterval(checkingActiveOffer, 5000);
module.exports = Object.assign({ checkingdatabase })```
create DB.js file and share MongoDB connection
mongoose.connect(process.env.ENV_SERVEUR_MONGO_URL;, { useFindAndModify: false, useUnifiedTopology: true, useNewUrlParser: true })
.then(function (res) {
console.log('Succeeded connected to: ' + process.env.ENV_SERVEUR_MONGO_URL;);
exports.isReady = true;
exports.connection = res;
exports.con = res.connection
})
Checking.js
var db = require('./DB')
app.get('/top', function (req, res) {
db.con.collection('top').find().sort({_id:-1}).toArray()
.then(r=>{
res.render('pages/top', { items: resultArray })
})
})
You can do it in two different ways:
1 - You pass the values you need as a prop to Checking function. So this way you would pass your envs and your mongo client when you invoke Checking function. Not advisable
2 - You can, and should, declare the things you need inside the Checking file. Your envs and mongoClient can just be required there, and it will make your code cleaner.
Take a look at this code and see if that suits your use case.

insert user data into mongodb database

I am trying to insert data into a mongodb database.
I am able to submit user data and display it with...
app.get('/process_get', function (req, res) {
response = {
first_name:req.query.firstName,
last_name:req.query.lastName,
username:req.query.userName,
password:req.query.password,
email:req.query.email
};
console.log(response);
res.end(JSON.stringify(response));
})
I then opened a connection with mongodb and created a "test" collection successfully...
MongoClient.connect("mongodb://localhost:27017/exampleDb", function(err, db) {
if(err) { return console.dir(err); }
if(!err) { console.log("MongoDB server is connected!") }
var collection = db.collection('test');
})
I tried "collection.insert({name:req.query.firstName});"
but this obviously didn't work because no "req". How do I make the inputs global
so I can simply insert them?
You don't have to do this within the database connection callback. Simply connect to your database in the process and then invoke the models.
//Setup Server and connect to mongoDB
var app = require('express')();
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
mongoose.connect('mongodb://localhost:27017/exampleDb');
//Create the model
var testSchema = mongoose.Schema({
..
});
var Test = mongoose.model('test', testSchema);
//Now use the model to save the object in the route controller
app.get('/process_get', function (req, res) {
response = {
.. //build the object based on some input or pas req.body directly
};
console.log(response);
new Test(response).save().then(function(result) {
res.end(JSON.stringify(result));
});
});
NB! You should split this logic out in different files to keep your project easier to maintain. The only reason for me to have it all in one file is to remove complexity.

mongoose schema with dynamic nested Object

I'm trying to create a Document Schema where I would have a dynamic Object. Example:
var ModuleSchema = new Schema({
name : String,
description : String,
type : String,
age : String,
options : {}
});
Is it possible to do the
options : {}
like that? with any arbitrary attributes inside. I'm getting TypeError: Cannot read property 'find' of undefined when I try to access a route /api/something to get all the documents in the collection. It might be because of the way I've defined the schema. any ideas?
EDIT:
var Module = require('../models/module');var auth =require('../config/auth');module.exports = function(router,Module){
router
.get('/api/modules' , auth.checkAuth, function(req,res){
Module.find(function(err,modules){
if(err){
res.send(err);
}else{
res.json(modules);
}
});
})
.post('/api/modules' , auth.checkAuth,function(req,res){
var module = new Module();
console.log(req.body);
module.name = req.body.name;
module.type = req.body.type;
module.description = req.body.description;
module.age = req.body.filename;
module.options = req.body.options;
module.save(function(err,module){
if(err){
res.send(err);
}else{
res.json({ id : module._id});
}
});
});
I use something like this.
// Importing the Users Mongoose Scheme
var User = require('../app/models/user');
var Feed = require('../app/models/ufeed');
module.exports = function(app) {
// A Route to get all users info
app.get('/user/all', function(req, res) {
// use mongoose to get all users in the database
User.find(function(err, user)
{
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
{
res.send(err);
}
// return all todos in JSON format
res.json(user);
});
});
Within my server.js file I am creating an app like so.
var app = express();
And then passing it to my routes file.
require('./app/routes.js')(app); // load our routes and pass in our app
I hope this helps.

Parsing nested JSON using body-parser and express

I have an iOS app which is sending a JSON packet to a webserver. The webserver code looks like this:
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var app = express();
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("MongoDB connection is open.");
});
// Mongoose Schema definition
var Schema = mongoose.Schema;
var LocationSchema = new Schema({
X: Number,
Y: Number,
Orientation: Number,
UserID: String,
Time: String
});
// Mongoose Model definition
var LocationsCollection = mongoose.model('locations', LocationSchema);
// create application/json parser
var jsonParser = bodyParser.json();
// URL management
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.post('/update', jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400);
else {
console.log(req.body);
}
});
// Start the server
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('App listening at %s:%s',host, port)
});
The key part is the app.post method which processes the incoming http request being sent from my iOS app. At the moment, the method which prints the req.body to the console looks like this:
{
datapoint_1:
{ timestamp: '2015-02-06T13:02:40:361Z',
x: 0.6164286615466197,
y: -0.6234909703424794,
id: 'B296DF8B-6489-420A-97B4-6F0F48052758',
orientation: 271.3345946652066 },
datapoint_2:
{ timestamp: '2015-02-06T13:02:40:961Z',
x: 0.6164286615466197,
y: -0.6234909703424794,
id: 'B296DF8B-6489-420A-97B4-6F0F48052758',
orientation: 273.6719055175781 }
}
So, you can see the request is a nested JSON object. Ideally, I'd like to loop through the request objects (ie. the datapoints) and insert those into the mongoDB database (via mongoose). However, I can't seem to figure out how to do much of anything with the req.body. I can't seem to create a loop to iterate through the request or how to properly parse the nested JSON file so it matches the mongoose schema. Can anyone provide some guidance on how to insert these datapoints into the mongoose database?
Set body-parser's extended property to true to allow parsing nested objects.
var express = require('express');
var app = express()
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
Answering my own question. But, after figuring out how to access the key/value pairs inside the nested JSON object... it became relatively easy to figure out the rest. The updated app.post function now looks like this:
app.post('/update', jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400);
else {
for(var datapoint in req.body){
//create new instance of LocationCollection document
var point = new LocationsCollection({
X:Number(req.body[datapoint]["x"]),
Y:Number(req.body[datapoint]["y"]),
Orientation:Number(req.body[datapoint]["orientation"]),
Time:req.body[datapoint]["timestamp"],
UserID:req.body[datapoint]["id"]
});
//insert the newly constructed document into the database
point.save(function(err, point){
if(err) return console.error(err);
else console.dir(point);
});
}
}
});
I can test if this worked by putting the following method inside the callback function once the mongodb connection is first established:
//Find all location points and print to the console.
console.log("Searching for all documents in Location Points Collection");
LocationsCollection.find(function(err,data){
if(err) console.error(err);
else console.dir(data);
});
This will print any documents that have been previously added to the database. Hopefully this helps.
Try somthing like this.
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json({limit:1024*1024, verify: function(req, res, buf){
try {
JSON.parse(buf);
} catch(e) {
res.send({
error: 'BROKEN_JSON'
});
}
}}));
It should be a simple for (var key in obj) loop:
app.post('/update', jsonParser, function (req, res) {
var locationObject = req.body(),
insertObjects = [],
key;
for (key in locationObject) { // loop through each object and insert them into our array of object to insert.
insertObjects.push(locationObject[key]);
}
if (!insertObjects.length) { // if we don't have any object to insert we still return a 200, we just don't insert anything.
return res.status(200).send({
success: true,
message: 'Nothing inserted, 0 locations in POST body',
count: 0;
});
}
LocationsCollection.create(insertObjects, function (err, res) {
if (err) {
return res.status(400).send({
success: false,
message: err.message
});
}
// we have successfully inserted our objects. let's tell the client.
res.status(200).send({
success: true,
message: 'successfully inserted locations',
count: insertObjects.length;
});
});
});
Mongo allows for inserting multiple documents with a single callback, which makes this a lot easier.
This also checks the schema to ensure only proper documents are created.

chaining database queries using promise in node.js

I'm trying to use the spread method to accumulate promised results that I've read in this thread with Q.js. It works in another block of code but not in the following app.get example. I want to chain queries using Sequelize and mongoose and pass all the returned data to the spread method. Here's my attempt:
var db = require('./db/managedb'); // Sequelize
var mongo_models = require('./db/mongo_model')(mongoose);
var WB = mongo_models.Webdata,
Est = mongo_models.Estimate;
app.get('/p/:tagId', function(req, res){
var filename = req.param("tagId");
var mysql = db.db.query('CALL procedure()').then(function(rows) {
console.log(rows);
}); // Sequelize
var nosql = WB.find().exec(function(err,k){
console.log(k);
}) // Mongoose
var nosql2 = Est.find().exec(function(err,la){
console.log(la);
}) // Mongoose
Q.try(function(){
return mysql
}).then(function(mysqls){
return [ mysqls,nosql]
}).then(function(mysqls,nosqls){
return [mysqls,nosqls,nosql2]
}).spread(function(mysqls,nosqls,nosql2s){
res.render(filename+'.html', {my:mysqls,wb:nosqls,est:nosql2s})
}).catch(function(error){
console.log('fail')
})
})
I'm just getting a blank page with Cannot GET /p/5 and there's no "fail" shown in the console.log. Here's my original code that works, but it's suffering from callback hell.
app.get('/p/:tagId', function(req, res){
var filename = req.param("tagId");
db.db.query('CALL procedure()').then(function(rows) {
WB.find().exec(function(err,wb){
Est.find().exec(function(err,est){
res.render(filename+'.html', {my:rows,wb:wb,est:est})
})
})
}).catch(function (error) {
console.log('own: database error');
})
})
You can try using them as proxies:
app.get('/p/:tagId', function(req, res){
var filename = req.param("tagId");
var rows = db.db.query('CALL procedure()');
var wb = WB.find().exec();
var est = Est.find().exec();
Promise.props({my: rows, wb: wb, est: est}).then(function(obj){
res.render(filename+'.html', obj)
}).catch(function (error) {
console.log('own: database error'); // not sure I'd just supress it
});
});
Bluebird is already available through sequelize if you don't have it in your project.
Alternatively, you don't have to put them in specific variables:
app.get('/p/:tagId', function(req, res){
var filename = req.param("tagId");
Promise.props({
my: db.db.query('CALL procedure()'),
wb: WB.find().exec(),
est: Est.find().exec()
}).then(function(obj){
res.render(filename+'.html', obj);
}).catch(function (error) {
console.log('own: database error'); // not sure I'd just supress it
});
});

Categories