98

I returned mongoose docs as json in this way:

UserModel.find({}, function (err, users) {
    return res.end(JSON.stringify(users));
}

However, user.__proto__ was also returned. How can I return without it? I tried this but not worked:

UserModel.find({}, function (err, users) {
    return res.end(users.toJSON());    // has no method 'toJSON'
}
Trantor Liu
  • 8,770
  • 8
  • 44
  • 64

10 Answers10

172

You may also try mongoosejs's lean() :

UserModel.find().lean().exec(function (err, users) {
    return res.end(JSON.stringify(users));
});
ecdeveloper
  • 2,777
  • 1
  • 22
  • 16
60

Late answer but you can also try this when defining your schema.

/**
 * toJSON implementation
 */
schema.options.toJSON = {
    transform: function(doc, ret, options) {
        ret.id = ret._id;
        delete ret._id;
        delete ret.__v;
        return ret;
    }
};

Note that ret is the JSON'ed object, and it's not an instance of the mongoose model. You'll operate on it right on object hashes, without getters/setters.

And then:

Model
    .findById(modelId)
    .exec(function (dbErr, modelDoc){
         if(dbErr) return handleErr(dbErr);

         return res.send(modelDoc.toJSON(), 200);
     });

Edit: Feb 2015

Because I didn't provide a solution to the missing toJSON (or toObject) method(s) I will explain the difference between my usage example and OP's usage example.

OP:

UserModel
    .find({}) // will get all users
    .exec(function(err, users) {
        // supposing that we don't have an error
        // and we had users in our collection,
        // the users variable here is an array
        // of mongoose instances;

        // wrong usage (from OP's example)
        // return res.end(users.toJSON()); // has no method toJSON

        // correct usage
        // to apply the toJSON transformation on instances, you have to
        // iterate through the users array

        var transformedUsers = users.map(function(user) {
            return user.toJSON();
        });

        // finish the request
        res.end(transformedUsers);
    });

My Example:

UserModel
    .findById(someId) // will get a single user
    .exec(function(err, user) {
        // handle the error, if any
        if(err) return handleError(err);

        if(null !== user) {
            // user might be null if no user matched
            // the given id (someId)

            // the toJSON method is available here,
            // since the user variable here is a 
            // mongoose model instance
            return res.end(user.toJSON());
        }
    });
eAbi
  • 3,220
  • 4
  • 25
  • 39
  • 3
    It's the best way to go. – Daniel Kmak Dec 05 '14 at 20:08
  • @eAbi both toJSON and toObject are not defined – OMGPOP Feb 17 '15 at 08:13
  • @OMGPOP both toJSON and toObject are methods defined on mongoose model instances. You can either provide your usage example or post another question on stackoverflow. Both toJSON and toObject methods were not deprecated/removed regardless of Mongoose version used, as far as I know. – eAbi Feb 17 '15 at 09:58
  • @eAbi it is not there. the asker also has the same problem. Are you sure you are calling toJSON instead of JSON.stringify()? – OMGPOP Feb 18 '15 at 02:25
  • 2
    @OMGPOP Yes I am sure that I am using toJSON method. The difference between OP's usage example and mine, is that in OP's question the returned `users` variable is an array of mongoose instances. You must iterate through the array and call the toJSON method on each instance. In my example I am using the findById method which directly passes the found mongoose instance to the callback function. Then you can directly call the toJSON (or toObject) method on this instance. – eAbi Feb 18 '15 at 10:38
  • @OMGPOP I have updated my answer where I am explaining the difference between OP's usage and mine, and why I could call the toJSON method and OP couldn't. – eAbi Feb 18 '15 at 10:54
  • I had the same problem, since most of us return array of objects we need to iterate and call toJSON function on each of the objects. I had to do this I had the same problem, since most of us return array of objects we need to iterate and call toJSON function on each of the objects. I had to do this var allbooks = []; mybooks.forEach(function (val) { allbooks.push(val.toJSON()); }); – Sharjeel Ahmed Jul 13 '15 at 09:41
  • particularly useful if you have nested array which has that __v field in it and you want to get rid of that – kboom Jan 05 '17 at 16:47
29

First of all, try toObject() instead of toJSON() maybe?

Secondly, you'll need to call it on the actual documents and not the array, so maybe try something more annoying like this:

var flatUsers = users.map(function() {
  return user.toObject();
})
return res.end(JSON.stringify(flatUsers));

It's a guess, but I hope it helps

Jamund Ferguson
  • 16,721
  • 3
  • 42
  • 50
17
model.find({Branch:branch},function (err, docs){
  if (err) res.send(err)

  res.send(JSON.parse(JSON.stringify(docs)))
});
Andrew Homeyer
  • 7,937
  • 5
  • 33
  • 26
Fabio Guerra
  • 722
  • 6
  • 13
8

I found out I made a mistake. There's no need to call toObject() or toJSON() at all. The __proto__ in the question came from jquery, not mongoose. Here's my test:

UserModel.find({}, function (err, users) {
    console.log(users.save);    // { [Function] numAsyncPres: 0 }
    var json = JSON.stringify(users);
    users = users.map(function (user) {
        return user.toObject();
    }
    console.log(user.save);    // undefined
    console.log(json == JSON.stringify(users));    // true
}

doc.toObject() removes doc.prototype from a doc. But it makes no difference in JSON.stringify(doc). And it's not needed in this case.

Trantor Liu
  • 8,770
  • 8
  • 44
  • 64
4

Maybe a bit astray to the answer, but if anyone who is looking to do the other way around, you can use Model.hydrate() (since mongoose v4) to convert a javascript object (JSON) to a mongoose document.

An useful case would be when you using Model.aggregate(...). Because it is actually returning plain JS object, so you may want to convert it into a mongoose document in order to get access to Model.method (e.g. your virtual property defined in the schema).

PS. I thought it should have a thread running like "Convert json to Mongoose docs", but actually not, and since I've found out the answer, so I think it is not good to do self-post-and-self-answer.

Leo Li
  • 247
  • 4
  • 20
2

You can use res.json() to jsonify any object. lean() will remove all the empty fields in the mongoose query.

UserModel.find().lean().exec(function (err, users) { return res.json(users); }

Pruthvi
  • 21
  • 1
  • 2
2

Try this options:

  UserModel.find({}, function (err, users) {
    //i got into errors using so i changed to res.send()
    return res.send( JSON.parse(JSON.stringify(users)) );
    //Or
    //return JSON.parse(JSON.stringify(users));
  }
Tinashe
  • 1,052
  • 12
  • 20
Dudi
  • 3,069
  • 1
  • 27
  • 23
2

It worked for me:

Products.find({}).then(a => console.log(a.map(p => p.toJSON())))


also if you want use getters, you should add its option also (on defining schema):

new mongoose.Schema({...}, {toJSON: {getters: true}})

yaya
  • 7,675
  • 1
  • 39
  • 38
0

Was kinda laughing at how cumbersome this was for a second, given that this must be extremely common.

Did not bother digging in the docs and hacked this together instead.

        const data =   await this.model.logs.find({ "case_id": { $regex: /./, $options: 'i' }})              
        let res = data.map(e=>e._doc)
        res.forEach(element => {
            //del unwanted data
            delete element._id
            delete element.__v
        });
        return res
  1. First i get all docs which have any value at all for the case_id field(just get all docs in collection)
  2. Then get the actual data from the mongoose document via array.map
  3. Remove unwanted props on object by mutating i directly
hpl002
  • 530
  • 4
  • 7