evilReiko
evilReiko

Reputation: 20503

Node.js + MongoDB: insert one and return the newly inserted document

I'm wondering if there is a way to insert new document and return it in one go.

This is what I'm currently using:

db.collection('mycollection').insertOne(options, function (error, response) {
    ...
});

Upvotes: 54

Views: 71192

Answers (10)

Daniel Valencia
Daniel Valencia

Reputation: 625

You can return the doc that you insert with the id

async insertProduct(product) {
  const record = await db.collection("products").insertOne(product);
  return {id: record.insertedId, ...product }
}

Upvotes: 6

Normando Hall
Normando Hall

Reputation: 11

Latest v4 behaviour

As Lauren said in official mongodb forum, this is the expected behaviour. I copy here her response:

It is new in driver v4 that our driver is compliant with the MongoDB CRUD spec

When you insertOne you now get the insertedId, so that should provide the only “new” part of the document that’s handled by the database.

    const myDoc = { a: 1 }
    myDoc._id = (await c.insertOne(myDoc)).insertedId
    // myDoc is now the same as the doc inserted into mongodb 

Upvotes: 1

renan
renan

Reputation: 347

For those who use MongoDB driver 4.x I found a workaround with findOneAndUpdate:

      const toInsert = {
        _id: mongo.ObjectId(),
        someField: 'hello',
        someOtherField: 'world'
      };
      const options = { upsert: true, returnDocument: 'after' };
      const { value: document } = await db.collection.findOneAndUpdate(
        toInsert,
        { $set: {} },
        options
      );

Notice that the _id in toInsert is a newly generated ObjectId.

The update is empty ({ $set: {} }) and does nothing as we don't need to need to update, we just want to upsert our document. It's still needed because the update cant be null or an empty object.

Because of the returnDocument option, the newly created document will be return as value in the result.


An other solution, in order to avoid an empty update, is to use $setOnInsert:

      const toInsert = { someField: 'hello', someOtherField: 'world' };
      const options = { upsert: true, returnDocument: 'after' };
      const { value: document } = await db.collection.findOneAndUpdate(
        { _id: mongo.ObjectId() },
        { $setOnInsert: toInsert },
        options
      );

Upvotes: 11

Shaishab Roy
Shaishab Roy

Reputation: 16805


UPDATE 2021: This approach no longer works with the MongoDB driver 4.x. The return result of the insertOne only contains an ID and acknowledgement flag: https://mongodb.github.io/node-mongodb-native/4.1/interfaces/InsertOneResult.html

With this change, there is NO way to accomplish the required behaviour. One should either do another DB request or combine the returned insertId and original object data.


The response result contains information about whether the command was successful or not and the number of records inserted.

If you want to return inserted data, you can try response.ops, for example:

db.collection('mycollection').insertOne(doc, function (error, response) {
    if(error) {
        console.log('Error occurred while inserting');
       // return 
    } else {
       console.log('inserted record', response.ops[0]);
      // return 
    }
});

Official documentation for insertOne:

http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertOne

The callback type:

http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~insertOneWriteOpCallback

The result type:

http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~insertOneWriteOpResult

Upvotes: 104

sidonaldson
sidonaldson

Reputation: 25314

UPDATE 2021: This approach no longer works with the MongoDB driver 4.x. The return of the insertOne only contains an ID and acknowledgement flag

I wanted to still use .then() to resolve by insert so I ended up wrapping the everything in it's own promise.

 return new Promise((resolve, reject) => {
     db.collection('entries').insertOne({ entry }, (err, res) => {
     if (err) {
       console.log('error', err);
       reject(null);
     } else {
       resolve(res.ops[0]);
     }
   });
 });

then I could just do

 insertEntry({}).then(entry=>{})

Upvotes: 0

Pawan Bishnoi
Pawan Bishnoi

Reputation: 2157

Try This

try {
    let collection = db.collection('collection_name'); let { ops: inserted } = 
    await collection.insertOne({ data: object });
    // can access array of inserted record like :
    console.log(inserted)
 } catch (error) {
    // log errors
 }

Upvotes: 0

Rishi Raj
Rishi Raj

Reputation: 422

Posting this as this might be helpful for someone. You can find the updated object like this:

await req.db
    .collection('users')
    .insertOne({ email, password: hashedPassword, name  })
    .then(({ ops }) => ops[0]);

Upvotes: 1

Naveen Kumar V
Naveen Kumar V

Reputation: 2819

The following code worked for me, in MongoDB version 2.2.33.

db.collection("sample_collection").insertOne({
   field1: "abcde"
}, (err, result) => {
   if(err) console.log(err);
   else console.log(result.ops[0].field1)
}

Upvotes: 5

Volodymyr Synytskyi
Volodymyr Synytskyi

Reputation: 4055

You could use mongojs to do this.

db.collection('mycollection').save(doc, function(error, response){
  // response has _id
})

Upvotes: 0

mrunde
mrunde

Reputation: 682

You could use mongoose to do this. With the save method you can insert a document and return it on success. Here is an example from the mongoose documentation:

product.save(function (err, product, numAffected) {
  if (err) {
    // Handle error...
  } else {
    // Do something with the returned document...
  }
})

Upvotes: 0

Related Questions