Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace the ObjectId ref. with with the actual object from MongoDB (idealy on the server side)?

Here is the schema of the principal object:

var newsSchema = new Schema({
    headline: String,
    paragraph: String,
    imgURI: String,
    imgThumbURI: String,
    imgCaption: String,
    addedOn: Date,
    addedBy: {
        type: ObjectID,
        ref: 'usr'
    }
});
var News = mongoose.model('news', newsSchema);

...and the schema for the addedBy:

var usr = new Schema({
    username: String,
    avatar: {
        type: ObjectID,
        ref: 'avtr'
    },
    href: String
});
var UserModel = mongoose.model('usr', usr);

So far so good. All works. Then in Angular client I retrieve a news object, but the addedBy value is not the desired object, but an ObjectId:

{
    "headline":"Shocking news from the Neverland!",
    ...
    "addedBy":"520e9aac9ca114914c000003", // <-- the offender!!
    "addedOn":"2013-08-16T21:33:32.294Z",
    "_id":"520e9aac9ca114914c000001",
    "__v":0
}

When I want an object like this:

{
    "headline":"Shocking news from the Neverland!",
    ...
    "addedBy":{
        "username":"Peter"
        "avatar":{
            "src":"../images/users/avatars/avatar1.png", 
            "ststus":"happy"}
        }
    "addedOn":"2013-08-16T21:33:32.294Z",
    "_id":"520e9aac9ca114914c000001",
    "__v":0
}

So yes, I want to all (no mater how deeply) nested ObjectId's be replaced with their respective objects from the DB, before the principal object is sent to the angular client. The API I am building is deep and complex and it would be nice if the angular client could to receive from my Express server an object which is ready to be thrown into a scope.
How do I change the following '/news' route:

app.get('/news', function(req, res, next){
    News.
        find().
        exec(function(err, nws){
            if(err) {res.writeHead(500, err.message)}
            res.send(nws);
        });
});

to accomplish just that, so I can fully access the complete (nested) object from angular like this:

angular.module('App', ['ngResource'])
    .controller('NewsCtrl', function($scope, $resource){
        var News = $resource('/news');
        var news = News.query();
        $scope.news = news;
    });

and then on the website access the api like this:

<img class="avatar-img" src="{{ news[0].addedBy.avatar.src }}">

I very much appreciate your time, cheers Jared

like image 975
Jared Tomaszewski Avatar asked Aug 17 '13 02:08

Jared Tomaszewski


People also ask

How to get object ID in MongoDB?

1 Create ObjectId. To create a new objectID manually within the MongoDB you can declare objectId as a method. ... 2 Define Specific ObjectId Hexadecimal. If you want to define your own unique hexadecimal value then MongoDB will enable you to perform this action. 3 Get ObjectId Hexadecimal String. ...

What is the default primary key for MongoDB document?

ObjectId : ObjectId class is a 12 byte binary BSON type, in which 4 bytes of timestamp of creation, 5 bytes of random value and 3 bytes of incrementing counter. ObjectId is the default primary key for MongoDB document and usually found in “_id” field. eg : { "_id" : ObjectId ("54759eb3c090d83494e2d804") }

What is objectId in pymongo?

ObjectId: ObjectId class is a 12-byte binary BSON type, in which 4 bytes of the timestamp of creation, 5 bytes of a random value, and 3 bytes of incrementing counter. ObjectId is the default primary key for MongoDB documents and is usually found in “_id” field. PyMongo: PyMongo is a native Python driver for MongoDB.

What is the use of MongoDB?

MongoDB is flexible for storing semi-structured and unstructured data. MongoDB is used for high-volume data storage and can scale horizontally. ObjectId: ObjectId class is a 12-byte binary BSON type, in which 4 bytes of the timestamp of creation, 5 bytes of a random value, and 3 bytes of incrementing counter.


1 Answers

As @WiredPrairie said, you need to use the populate function Populate Mongoose Documentation

Your query should look like this:

app.get('/news', function(req, res, next){
    News.
        find().
        populate("addedBy").
        exec(function(err, nws){
            if(err) {res.writeHead(500, err.message)}
            res.send(nws);
        });
});

There are plenty of different things that you can do with populate, for example to bring only the username field of the "addedBy" document, you can do

populate("addedBy","username")

or if you don't want bring one specific field, doing something like this:

populate("addedBy","-username")
like image 124
Jonathan P. Diaz Avatar answered Dec 15 '22 01:12

Jonathan P. Diaz