6
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
    if(err) console.log(err);

    console.log("DOC " + doc)

    if(doc.status) {
        // FOUND ROOM SATTUS IS TRUE LOGIC 
        console.log(doc);
        // return callback(true)
    }
 });

Above query will return to me the actual document that's updated or inserted but I can't check exactly which one it is. If I do an update instead of findOneandUpdate I'm returned this

{
    ok: 1,
    nModified: 0,
    n: 1,
    upserted: [ { index: 0, _id: 55df883dd5c3f7cda6f84c78 } ]
} 

How do I return both the document and the write result or at least the upserted field from the write result.

Thomas Bormans
  • 5,156
  • 6
  • 34
  • 51
Sarodh Uggalla
  • 293
  • 1
  • 4
  • 15
  • If it is "upserted" then the only content that can possibly be in the document is the content you sent in the operation. In this case the "RoomName", "status" and "userNum" fields, and all with the content you specified here. The only thing other than what you send that can possibly be created is the `_id` value. So this is why that is the only thing returned. Understand? You don't need anything returned since your the one that already has all the values. – Blakes Seven Aug 27 '15 at 23:12
  • 1
    Right but for the findOneAndUpdate if I say new:true , is there no way to distinguish whether that returning document was inserted or found? If however I don't include new:true then doc in this case would return null when the doc cant be found and then i assume it's inserted but im wondering if there's a better way about it look – Sarodh Uggalla Aug 27 '15 at 23:18
  • You clearly do not understand. Read what I said again. You send the values for three fields, you get told a new document was created and the new _id of that document. No other fields are created other than the values you asked it to set. You already know the values, therefore there is no point in returning a document that just contains those values. That is how it works. – Blakes Seven Aug 27 '15 at 23:27
  • I do not get the write result object for findOneAndUpdate that is only for update I was wondering how to get that for the findOneAndUpdate along with the document. – Sarodh Uggalla Aug 27 '15 at 23:29
  • but i see it's not possible – Sarodh Uggalla Aug 27 '15 at 23:35
  • The point is **it's not necessary**. And that is what you need to understand. Again if the document is "modified" then you "will" get the modified document returned – Blakes Seven Aug 27 '15 at 23:44
  • Yea, it does seem redundant. So I can use either update or findOneAndUpdate for the same means. Is there any preference here? – Sarodh Uggalla Aug 27 '15 at 23:59
  • Huh? Two completely different things. The purpose of `.update()` is to simply update, and possibly for multiple document. `.findOneAndUpdate()` also does exactly what it is named, and will either return the "modified" document or the "original" when a modification is made. If you want that return data for "modified" documents and one at a time, then that is what you use. BTW, the default `new: false` is set that way so it is easy to "tell" if the modification you sent actually changed anything, since the data you asked to change will have a different value in the document returned. – Blakes Seven Aug 28 '15 at 00:13
  • If I use `upsert: true` with `.update()` or `.findOneAndUpdate()` they will both do what I'm trying to do which is pretty much a findOrCreate since I'm not actually updating any information. – Sarodh Uggalla Aug 28 '15 at 00:20
  • Well "findOrCreate" pretty much implies fetching a document, so the correct term would be "updateOrCreate" which specifies the difference between the two. Both either "modify" on match or "upsert" where there is no match. So the difference here is in the word "find" – Blakes Seven Aug 28 '15 at 00:28
  • It seems I will need the fetch component so I'll go with `findOneAndUpdate()`, thanks for clarifying. – Sarodh Uggalla Aug 28 '15 at 00:35
  • So there is no way to get the _id field of your upserted document while still being able to check whether you inserted or not when using `findOneAndUpdate()` ? – Sarodh Uggalla Aug 30 '15 at 05:37

5 Answers5

6

As of 8 August 2019 (Mongoose Version 5.6.9), the property to set is "rawResult" and not "passRawResult":

M.findOneAndUpdate({}, obj, {new: true, upsert: true, rawResult:true}, function(err, d) {
    if(err) console.log(err);
    console.log(d);
});

Output:

{ lastErrorObject:
   { n: 1,
     updatedExisting: false,
     upserted: 5d4befa6b44b48c3f2d21c75 },
  value: { _id: 5d4befa6b44b48c3f2d21c75, rating: 4, review: 'QQQ' },
  ok: 1 }

Notice also the result is returned as the second parameter and not the third parameter of the callback. The document can be retrieved by d.value.

Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
4

Alright so my main problem was that I couldn't get the _id of the document I inserted without not being able to check whether if it was updated/found or inserted. However I learned that you can generate your own Id's.

id = mongoose.Types.ObjectId();    
Chatrooms.findOneAndUpdate({Roomname: room.Roomname},{ $setOnInsert: {_id: id, status: true, userNum: 1}}, {new: true, upsert: true}, function(err, doc) {
        if(err) console.log(err);

        if(doc === null) {

           // inserted document logic 
           // _id available for inserted document via id 
        } else if(doc.status) {

         // found document logic 
        }
     });

Update

Mongoose API v4.4.8

passRawResult: if true, passes the raw result from the MongoDB driver as the third callback parameter.

Sarodh Uggalla
  • 293
  • 1
  • 4
  • 15
4

Version 4.1.10 of Mongoose has an option called passRawResult which if set to true causes the raw parameter to be passed. Leaving out this option seems to default to false and cause raw to always be undefined:

passRawResult: if true, passes the raw result from the MongoDB driver as the third callback parameter

http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

Daniel Flippance
  • 7,734
  • 5
  • 42
  • 55
0

I'm afraid Using FindOneAndUpdate can't do what you whant because it doesn't has middleware and setter and it mention it the docs:

Although values are cast to their appropriate types when using the findAndModify helpers, the following are not applied:

  • defaults
  • Setters
  • validators
  • middleware

http://mongoosejs.com/docs/api.html search it in the findOneAndUpdate
if you want to get the docs before update and the docs after update you can do it this way :

Model.findOne({ name: 'borne' }, function (err, doc) {
if (doc){ 
  console.log(doc);//this is ur document before update
  doc.name = 'jason borne';
  doc.save(callback); // you can use your own callback to get the udpated doc
}
})

hope it helps you

Gujarat Santana
  • 9,854
  • 17
  • 53
  • 75
0

I don't know how this got completely off track, but there as always been a "third" argument response to all .XXupdate() methods, which is basically the raw response from the driver. This always tells you whether the document is "upserted" or not:

Chatrooms.findOneAndUpdate(
   { "Roomname": room.Roomname },
   { "$setOnInsert": { 
      "status": true, "userNum": 1
   }},
   { "new": true, "upsert": true },
   function(err, doc,raw) {
    if(err) console.log(err);

    // Check if upserted
    if ( raw.lasErrorObject.n == 1 && !raw.lastErrorObject.updatedExisting ) {
        console.log("upserted: %s", raw.lastErrorObject.upserted);
    }

    console.log("DOC " + doc)

    if (doc.status) {
        // FOUND ROOM SATTUS IS TRUE LOGIC 
        console.log(doc);
        // return callback(true)
    }
});

Which will tell you the _id of the document that was just upserted.

From something like this in the "raw" response:

{ lastErrorObject:
   { updatedExisting: false,
     n: 1,
     upserted: 55e12c65f6044f57c8e09a46 },
  value: { _id: 55e12c65f6044f57c8e09a46, 
           status: true,
           userNum: 1
           __v: 0 },
  ok: 1 }

Complete reproducible listing:

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

mongoose.connect('mongodb://localhost/test');

var testSchema = new Schema({
  name: String
});

var Test = mongoose.model('Test', testSchema, 'test');

async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },
    function(callback) {
      async.eachSeries(
        ["first","second"],
        function(it,callback) {
          console.log(it);
          Test.findOneAndUpdate(
            { "name": "Bill" },
            { "$set": { "name": "Bill" } },
            { "new": true, "upsert": true },
            function(err,doc,raw) {
              console.log(raw),
              console.log(doc),
              callback(err);
            }
          );
        },
        callback
      );
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

Which outputs:

first
{ lastErrorObject:
   { updatedExisting: false,
     n: 1,
     upserted: 55e2a92328f7d03a06a2dd6b },
  value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
  ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
second
{ lastErrorObject: { updatedExisting: true, n: 1 },
  value: { _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 },
  ok: 1 }
{ _id: 55e2a92328f7d03a06a2dd6b, name: 'Bill', __v: 0 }
Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • raw is undefined for me. any idea why? – Sarodh Uggalla Aug 30 '15 at 06:27
  • @SarodhUggalla Not possible. It is only ever undefined when there is no match or upsert. With `upsert:true` there is always a response. That is because this is where mongoose gets it's response from in the first place. You are doing something wrong/different. – Blakes Seven Aug 30 '15 at 06:31
  • `Chatrooms.findOneAndUpdate({Roomname: RoomHash.roomhash},{ $setOnInsert: { userNum: 1, status: true}}, {new: true,upsert: true}, function(err, doc, raw) { console.log("DOC: %j" , doc); console.log("RAW: %j", raw); if(err) console.log(err);` – Sarodh Uggalla Aug 30 '15 at 06:34
  • exactly the same as far as i can see. – Sarodh Uggalla Aug 30 '15 at 06:34
  • @SarodhUggalla What is your mongoose version? – Blakes Seven Aug 30 '15 at 06:35
  • I hope there's a reason for this because this is exactly what I need. – Sarodh Uggalla Aug 30 '15 at 06:47
  • @SarodhUggalla Attached a complete listing that is reproducible. Actually using latest 4.1.6 on install, but there should be no difference. You are doing something wrong. Use it to compare. I know it works and the listing output is exactly shown from running the provided code. I also know because I have been explaining the difference using "promises" here: http://stackoverflow.com/a/32282592/5031275 – Blakes Seven Aug 30 '15 at 06:58
  • first undefined { _id: 55e2aa26d5c3f7cda6f84cfd, name: 'Bill', __v: 0 } second undefined { _id: 55e2aa26d5c3f7cda6f84cfd, name: 'Bill', __v: 0 } – Sarodh Uggalla Aug 30 '15 at 07:01
  • @SarodhUggalla Dude. Brand new directory and npm init etc etc. That is what "reproducible" means. Get out of your own project directory and whatever problems you have caused there. That is the point here. – Blakes Seven Aug 30 '15 at 07:07
  • it worked this time though the version is mongoose@4.1.3 – Sarodh Uggalla Aug 30 '15 at 07:17
  • @SarodhUggalla Of course it does. Things work as designed. Things in your own project ie dependencies, plugins, your own code, are breaking the normal functionality. That's your job to sort out what the problem is. Add dependency tests to your projects in the future. ie. Make sure that basic things like this are not being broken. The issue is "Solved" BTW. If your project breaks it, then that is not up to the answer provided here to solve. Nor was it your question. – Blakes Seven Aug 30 '15 at 07:19
  • @SarodhUggalla As already stated. That is up to you to work out. Even asking another question without further investigation from yourself would be "too broad" a topic. I cannot see your whole codebase, so I don not know what you have done. But it is not mongoose versions. At least not within the 4.x series. – Blakes Seven Aug 30 '15 at 07:25
  • @SarodhUggalla Well you got an answer then. Don't forget to [accept](http://stackoverflow.com/help/accepted-answer) it. – Blakes Seven Aug 30 '15 at 07:57