【问题标题】:How can I retrieve an id from MongoDB create operation during a transaction?如何在事务期间从 MongoDB 创建操作中检索 id?
【发布时间】:2020-12-06 04:50:15
【问题描述】:

我正在尝试使用 Apollo Server 和 Mongoose 创建审计跟踪。当用户最初注册时,我会在用户集合中创建一个文档,并在历史集合中为他们提供的每条数据(用户名、密码、电子邮件等)创建一个文档。对于每个历史收集文档,我都包含用户文档的 id 以创建关系。完美运行。

但是,当我在其中添加交易时(见下文),用户文档的 userId 以未定义的形式返回,因此我无法将其添加到历史条目文档中。我假设在整个事务完成之前不会创建文档的 ID?

有什么想法吗?

Mutation: {
  register: async (_, { data }) => {

    // Start a mongo session & transaction
    const session = await mongoose.startSession()
    session.startTransaction()

    try {

      // Hash password and create user
      const hashedPassword = await bcrypt.hash(data.password, 12)
      const user = await User.create(
        [{ ...data, password: hashedPassword }],
        { session }
      )
      
      // Add history entries
      HistoryEntry.create([
      {
        user: user.id,
        action: 'registered'
      },
      {
        user: user.id,
        action: 'set',
        object: 'profile',
        instance: user.id,
        property: 'firstName',
        value: firstName
      },
      {
        user: user.id,
        action: 'set',
        object: 'profile',
        instance: user.id,
        property: 'lastName',
        value: lastName
      },
      {
        user: user.id,
        action: 'set',
        object: 'profile',
        instance: user.id,
        property: 'password'
      }
    ])

    if (loginType === 'email') {
      HistoryEntry.create({
        user: user.id,
        action: 'set',
        object: 'profile',
        instance: user.id,
        property: 'email',
        value: login
      })
    }

    if (loginType === 'mobile') {
      HistoryEntry.create({
        user: user.id,
        action: 'set',
        object: 'profile',
        instance: user.id,
        property: 'mobile',
        value: login
      })
    }

    // commit the changes if everything was successful
    await session.commitTransaction()
      return {
        ok: true,
        user
      }
    } catch (err) {
      // if anything fails above, rollback the changes in the transaction
      await session.abortTransaction()
      return formatErrors(err)
    } finally {
      // end the session
      session.endSession()
    }
  }
}

【问题讨论】:

  • ids可以完全在客户端生成,事务与此无关。

标签: mongodb mongoose apollo-server audit-trail


【解决方案1】:

如果您考虑一下,如果您还没有添加用户,如何添加 HistoryEntry?这不是你目前正在做的“历史”。我相信您在这里有两个选择 - 手动在用户上设置 _id new Schema({ _id: { type: Schema.ObjectId, auto: true }}),然后在事务中生成它:var userId = ObjectId(); 并用于用户和历史条目。

我相信第二个选项在这种情况下在语义上更正确 - 你应该附加到post-save hook

schema.post('save', function(doc) {
  console.log('%s has been saved', doc._id);
});

因此,每当创建用户时,都会触发保存后挂钩以更新历史记录。

【讨论】:

    【解决方案2】:

    最近遇到了同样的问题,希望您已经解决了。我可能会为未来的求职者添加这个。

    1. 创建函数后返回一个已创建文档的数组。
    const user = await User.create(
            [{ ...data, password: hashedPassword }],
            { session }
    );
    

    因此访问用户ID为user[0]._id

    1. 也将会话传递给HistoryEntry.create()
    HistoryEntry.create([{...},{...}], {session})
    

    注意:在这个用例中,我个人更喜欢@marek 第二个选项来使用保存后挂钩。

    【讨论】:

      猜你喜欢
      • 2019-10-25
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-18
      • 2020-09-09
      相关资源
      最近更新 更多