最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - why insertmany not working using mongoos with transactions? - Stack Overflow

programmeradmin4浏览0评论

I am trying to insert data using inertMany .but I am not able to insert the data why ?I am using mongoose session if any error occurred then I roll back changes

app.get("/saveData", async (req, res, next) => {
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    const data = [
      {
        empid: "Ad",
        id: 4,
        date: "19-Jul-2019"
      },
      {
        empid: "Bc",
        id: 56,
        date: "18-Jul-2019"
      },

      {
        empid: "C",
        id: 6,
        date: "11-Jul-2019"
      }
    ];
    console.log("before save");
    let saveBlog = await BlogPostModel.insertMany(data, { session }); //when fail its goes to catch
    await sessionmitTransaction();
    return res.send(saveBlog);
  } catch (error) {
    console.log(error);
    await session.abortTransaction();
    return res.status(400).send(error);
  }
});

I am trying to insert data using inertMany .but I am not able to insert the data why ?I am using mongoose session if any error occurred then I roll back changes

https://codesandbox.io/s/dreamy-bell-9u0bz

app.get("/saveData", async (req, res, next) => {
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    const data = [
      {
        empid: "Ad",
        id: 4,
        date: "19-Jul-2019"
      },
      {
        empid: "Bc",
        id: 56,
        date: "18-Jul-2019"
      },

      {
        empid: "C",
        id: 6,
        date: "11-Jul-2019"
      }
    ];
    console.log("before save");
    let saveBlog = await BlogPostModel.insertMany(data, { session }); //when fail its goes to catch
    await session.mitTransaction();
    return res.send(saveBlog);
  } catch (error) {
    console.log(error);
    await session.abortTransaction();
    return res.status(400).send(error);
  }
});
Share Improve this question asked Sep 28, 2019 at 7:56 user944513user944513 12.8k52 gold badges185 silver badges348 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

Since you don't appear to have understood the marked duplicate or the ment on your last question, here's a direct demonstration:

const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true, useUnifiedTopology: true };

mongoose.Promise = global.Promise;

mongoose.set('debug', true);
mongoose.set('useCreateIndex', true);
mongoose.set('useFindAndModify', false);

const blogPostSchema = new Schema({
  id: { type: Number, unique: true },
  empid: String,
  date: Date
});

const BlogPost = mongoose.model('BlogPost', blogPostSchema);

const sampleData = [
  { empid: "test13", id: 6, date: '11-Jul-2019' },
  { empid: "test123", id: 4, date: '19-Jul-2019' },
  { empid: "test13", id: 4, date: '18-Jul-2019' }
];

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {
    const conn = await mongoose.connect(uri, opts);

    // Clean data
    await Promise.all(
      Object.values(conn.models).map(m => m.deleteMany())
    );

    // Collections must existi in transactions
    await Promise.all(
      Object.values(conn.models).map(m => m.createCollection())
    );


    // With Transaction
    log("With Transaction");
    let session = await conn.startSession();
    session.startTransaction();

    try {
      await BlogPost.insertMany(sampleData, { session });
      await session.mitTransaction();
    } catch(e) {
      // Show the error and abort
      log({ err: e.errmsg, result: e.result.result.writeErrors });
      await session.abortTransaction();
    }

    log({ results: (await BlogPost.find()) });

    // No transaction
    log("Without Transaction");
    try {
      await BlogPost.insertMany(sampleData);
    } catch(e) {
      // Show the error
      log({ err: e.errmsg, result: e.result.result.writeErrors });
    }

    log({ results: (await BlogPost.find()) });


  } catch (e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }


})();

And the output:

Mongoose: blogposts.createIndex({ id: 1 }, { unique: true, background: true })
Mongoose: blogposts.deleteMany({}, {})
"With Transaction"
Mongoose: blogposts.insertMany([ { _id: 5d8f28ac462a1e1a8c6838a2, empid: 'test13', id: 6, date: 2019-07-10T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a3, empid: 'test123', id: 4, date: 2019-07-18T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a4, empid: 'test13', id: 4, date: 2019-07-17T14:00:00.000Z, __v: 0 } ], { session: ClientSession("650da06d23544ef8bc1d345d93331d1e") })
{
  "err": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
  "result": [
    {
      "code": 11000,
      "index": 2,
      "errmsg": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
      "op": {
        "_id": "5d8f28ac462a1e1a8c6838a4",
        "empid": "test13",
        "id": 4,
        "date": "2019-07-17T14:00:00.000Z",
        "__v": 0
      }
    }
  ]
}
Mongoose: blogposts.find({}, { projection: {} })
{
  "results": []
}
"Without Transaction"
Mongoose: blogposts.insertMany([ { _id: 5d8f28ac462a1e1a8c6838a5, empid: 'test13', id: 6, date: 2019-07-10T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a6, empid: 'test123', id: 4, date: 2019-07-18T14:00:00.000Z, __v: 0 }, { _id: 5d8f28ac462a1e1a8c6838a7, empid: 'test13', id: 4, date: 2019-07-17T14:00:00.000Z, __v: 0 } ], {})
{
  "err": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
  "result": [
    {
      "code": 11000,
      "index": 2,
      "errmsg": "E11000 duplicate key error collection: test.blogposts index: id_1 dup key: { id: 4 }",
      "op": {
        "_id": "5d8f28ac462a1e1a8c6838a7",
        "empid": "test13",
        "id": 4,
        "date": "2019-07-17T14:00:00.000Z",
        "__v": 0
      }
    }
  ]
}
Mongoose: blogposts.find({}, { projection: {} })
{
  "results": [
    {
      "_id": "5d8f28ac462a1e1a8c6838a5",
      "empid": "test13",
      "id": 6,
      "date": "2019-07-10T14:00:00.000Z",
      "__v": 0
    },
    {
      "_id": "5d8f28ac462a1e1a8c6838a6",
      "empid": "test123",
      "id": 4,
      "date": "2019-07-18T14:00:00.000Z",
      "__v": 0
    }
  ]
}

Note that when the transaction is in use there are no items inserted into the collection. Using the insertMany() with the default behavior of ordered: true will insert all batched items up until the point any error is encountered.

Note also as stated since you are indeed expecting an error you must include such a statement in it very own try..catch or similar error handler. Otherwise any error ( which is expected in the example case ) would simply fall to the outer catch, which of course in the demonstration simply exits the program.


Not actually in the question itself but something not actually mentioned in the demonstrations of How to use MongoDB transaction using Mongoose? is indeed that you should be aware that whlist a transaction is active you must also include the session attribute on any subsequent reads in order to see the changes made within that transaction.

For instance, the following would show no content in a collection:

let session = await conn.startSession();
session.startTransaction();

try {
  await BlogPost.insertMany(sampleData, { session });
  let documents = await BlogPost.find(); // This would return nothing
  await session.mitTransaction();
} catch(e) {
  // Show the error and abort
  log({ err: e.errmsg, result: e.result.result.writeErrors });
  await session.abortTransaction();
}

However including the session within a find() will actually show what is inserted:

try {
  await BlogPost.insertMany(sampleData, { session });
  // Actually includes the session and therefore the state
  let documents = await BlogPost.find({},{ session });

  await session.mitTransaction();
} catch(e) {
  // Show the error and abort
  log({ err: e.errmsg, result: e.result.result.writeErrors });
  await session.abortTransaction();
}

And of course that read would in this case be dependent on the insertMany() not failing for any reason, since any error would result in exiting to the catch before the next request was made.

Once a transaction is mitted, it is of course available to the global state of the connection. But whilst in progress only operations which include the same session information on which the transaction was started will have visibility of any changes implemented within that transaction.

For who get the error "Cannot read property 'map' of undefined" while passing session as option in inserMany, this errors e because your mongo is running as standalone servers, to fix this can refer npm package run-rs or following this answer to fix this: https://stackoverflow./a/60603587/9611273

发布评论

评论列表(0)

  1. 暂无评论