3

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?

8
  • You probably have to parse the JSON with JSON.parse if it's still a string Commented Feb 6, 2015 at 18:25
  • @adeneo Can you clarify a bit? I assumed that the body-parser middleware had already parsed the string into a JSON object. Commented Feb 6, 2015 at 18:30
  • Well, try it, do typeof req.body, I'm guessing you'll get string Commented Feb 6, 2015 at 18:31
  • @adeneo It came back as an object not string. Wouldn't that mean it's a JSON object? If it is a JSON object, can you recommend how to properly process it (to be able to insert it into a database) since it's a nested JSON object? Commented Feb 6, 2015 at 18:35
  • 2
    for (var key in obj) { ... } Commented Feb 6, 2015 at 18:55

4 Answers 4

12

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
}));
Sign up to request clarification or add additional context in comments.

Comments

3

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.

1 Comment

You could accept your answer if it is indeed the answer.
1

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'
        });
    }
}}));

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.