Search code examples
node.jsmongodbexpressmongoosemongoose-populate

mongoose population of documents from other collections


I'm trying to create some kind of relation in my API between Retailers and GeofencePoints. A retailer object should have a list of geofence points. I tried to follow the official docs: http://mongoosejs.com/docs/populate.html. I'm getting a http 200 response when I perform the query to PUT a geofence location for a retailer, but when I get the Retail object by the id, the geofencePoints list is still empty. What am I doing wrong? Here is my Code:

Routes

    app.route('/geofencePoints')
    .get(geofencePointController.GET)
    .post(geofencePointController.POST)
    .delete(geofencePointController.DELETE)

    app.route('/geofencePoints/:point_id')
    .get(geofencePointController.GETid)
    .put(geofencePointController.PUTid)
    .delete(geofencePointController.DELETEid);

    app.route('/retailers')
    .get(retailerController.GET)
    .post(retailerController.POST);

    app.route('/retailers/:retailer_id')
    .get(retailerController.GETid)
    .put(retailerController.PUTid)
    .delete(retailerController.DELETEid);

    app.route('/retailers/:retailer_id/geofencePoints')
    .put(geofencePointController.PUTgeofencesForRetailId);

geofencePointController.js

var GeofencePoint = require('../model/geofencePoint');
var Retailer = require('../model/retailer');

exports.GET = function (req, res) {
    GeofencePoint.find(function (err, points) {
        if (err)
            res.send(err);
        res.json(points);
    });
};

exports.POST = function (req, res) {
    var geofencePoint = new GeofencePoint();
    geofencePoint.name = req.body.name;
    geofencePoint.latitude = req.body.latitude;
    geofencePoint.longitude = req.body.longitude;
    geofencePoint.radius = req.body.radius;
    geofencePoint.save(function (err) {
        if (err)
            return res.json({ success: false, msg: 'Name already exists.' });
        res.json({ success: true, msg: 'Successful created new geofence.' });
    });
};

exports.DELETE = function (req, res) {
    GeofencePoint.remove({
    }, function (err, point) {
        if (err)
            res.send(err);
        res.json({ message: 'Successfully deleted all' });
    });
};

exports.GETid = function (req, res) {
    GeofencePoint.findById(req.params.point_id, function (err, point) {
        if (err)
            res.send(err);
        res.json(point);
    });
};

exports.PUTid = function (req, res) {
    GeofencePoint.findById(req.params.point_id, function (err, point) {
        if (err)
            res.send(err);
        point.name = req.body.name;
        point.latitude = req.body.latitude;
        point.longitude = req.body.longitude;
        point.radius = req.body.radius;
        point.save(function (err) {
            if (err)
                res.send(err);
            res.json({ message: 'Geofence location updated!' });
        });
    });
};

exports.DELETEid = function (req, res) {
    GeofencePoint.remove({
        _id: req.params.point_id
    }, function (err, point) {
        if (err)
            res.send(err);
        res.json({ message: 'Successfully deleted' });
    });
};

//===================================================================
//  JOINED DATA
//===================================================================

exports.PUTgeofencesForRetailId = function (req, res) {
    Retailer.find({}).populate(req.params.retailer_id).exec(function (err, geofencePoint) {
            if (err) return handleError(err);
        var geofencePoint = new GeofencePoint();
        geofencePoint.name = req.body.name;
        geofencePoint.latitude = req.body.latitude;
        geofencePoint.longitude = req.body.longitude;
        geofencePoint.radius = req.body.radius;
        geofencePoint.save(function (err) {
            if (err) return res.json({ success: false, msg: 'Something went wrong' });
        res.json({ success: true, msg: 'Success' });
        });
    });
};

retailerController.js

var Retailer = require('../model/retailer');

exports.GET = function (req, res) {
    Retailer.find(function (err, retailers) {
        if (err)
            res.send(err);
        res.json(retailers);
    });
};
exports.GETid = function (req, res) {
    Retailer.findById(req.params.retailer_id, function (err, retailer) {
        if (err)
            res.send(err);
        res.json(retailer);
    });
};
exports.POST = function (req, res) {
    var retailer = new Retailer();
    retailer.name = req.body.name;

    retailer.save(function (err) {
        if (err)
            return res.json({ success: false, msg: 'Name already exists.' });
        res.json({ success: true, msg: 'Successful created new retailer.' });
    });
};
exports.PUTid = function (req, res) {
    Retailer.findById(req.params.retailer_id, function (err, retailer) {
        if (err)
            res.send(err);
        retailer.name = req.body.name;

        retailer.save(function (err) {
            if (err)
                res.send(err);
            res.json({ message: 'Retailer updated!' });
        });
    });
};
exports.DELETEid = function (req, res) {
    Retailer.remove({
        _id: req.params.point_id
    }, function (err, retailer) {
        if (err)
            res.send(err);
        res.json({ message: 'Successfully deleted' });
    });
};

retailer.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var retailerSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    mail: {
        type: String,
    },
    telephone: {
        type: String,
    },
    street: {
        type: String,
    },
    housenumber: {
        type: String,
    },
    postalCode: {
        type: String,
    }, 
    city: {
        type: String,
    },
    slogan: {
        type: String,
    },
    geofencePoints : [{ 
        type: Schema.Types.ObjectId, 
        ref: 'GeofencePoint' }]
});

module.exports = mongoose.model('Retailer', retailerSchema);

geofencePoint.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var pointSchema = new Schema({
    name: {
        type: String,
        required: true
    },
    latitude: {
        type: Number,
        required: true
    },
    longitude: {
        type: Number,
        required: true
    },
    radius: {
        type: Number,
        required: true
    },
    duration: {
        type: Number,
    },
});

module.exports = mongoose.model('GeofencePoint', pointSchema);

I hope someone can explain what I am doing wrong. Thx


Solution

  • You need to save a reference to the new created GeofencePoint in your Retailer document.
    Also, I don't understand why you try to populate Retailer when you make an update (and I think you try to populate it wrong, the only element to populate here is indeed the geofencePoint, not Retailers).

    exports.PUTgeofencesForRetailId = function (req, res) {
    
        var geofencePoint = new GeofencePoint({
            name: req.body.name,
            latitude: req.body.latitude,
            longitude: req.body.longitude,
            radius: req.body.radius
        });
    
        geofencePoint.save(function (err, geofencePoint) {
            if (err) return res.json({ success: false, msg: 'Something went wrong' });
            Retailer.findById(req.params.retailer_id, function (err, retailer) {
                if (err) return handleError(err);
                retailer.geofencePoints.push(geofencePoint._id);
                retailer.save(function (err, retailer) {
                    if (err) return handleError(err);
                    res.json({ success: true, msg: 'Success' });
                });
            });
        });
    };
    

    There is certainly a better/more concise approach, accordingly to your app, but it gives an idea.