如何让 mongoDB 根据用户集合中提供的 _ids 为发送者和接收者填充交易集合的子字段

问题描述 投票:0回答:1

这是我的 Mongoose 架构,分别用于三个集合用户、帐户和交易:

const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true,
        unique: true,
        trim: true,
        lowercase: true,
        minLength: 3,
        maxLength: 30
    },
    password: {
        type: String,
        required: true,
        minLength: 6
    },
    firstName: {
        type: String,
        required: true,
        trim: true,
        maxLength: 50
    },
    lastName: {
        type: String,
        required: true,
        trim: true,
        maxLength: 50
    }
});

const accountSchema = new mongoose.Schema({
    user: {
        type: mongoose.Schema.Types.ObjectId, 
        ref: "User"
    },
    balance: {
        type: Number,
        minLength: 0,
        required: true
    }
})

const transactionSchema = new mongoose.Schema({
    sender: {
        _id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "User",
            required: true
        },
        firstName: {
            type: String,
            required: true
        },
        lastName: {
            type: String,
            required: true
        }
    },
    receiver: {
        _id: {
            type: mongoose.Schema.Types.ObjectId,
            ref: "User",
            required: true
        },
        firstName: {
            type: String,
            required: true
        },
        lastName: {
            type: String,
            required: true
        }
    },
    amount: {
        type: Number,
        required: true
    }
});

transactionSchema 的定义是这样的,希望 mongoose 能够理解,因为 _id 的 ref:“User”属性(不要在这个问题上评判我,chatGPT 是这样建议我的。而且,你可以评判我) ,自动填充发送者和接收者的名字和姓氏字段。

当前定义的 transactionsSchema 不允许发生以下转账逻辑:

accountRouter.post("/transfer", authMiddleware, async (req, res) => {
    const session = await mongoose.startSession();

    session.startTransaction();
    const { amount, to } = req.body;
    
    //...some logic that's not relevant to this question
    //...

    // Perform the transfer
    await AccountModel.updateOne({ user: req.body.userId }, { $inc: { balance: -amount } }).session(session);
    await AccountModel.updateOne({ user: to }, { $inc: { balance: amount } }).session(session);
    await TransactionModel.create({ sender: {_id: req.body.userId}, receiver: {_id: to}, amount: amount });

    // Commit the transaction
    await session.commitTransaction();
    res.json({
        message: "Transfer successful"
    });
});

它会抛出一个错误,指出需要firstName和lastName(我猜是在模式中指定的)。我尝试删除所需的属性,在这种情况下,交易有效...但新创建的记录中不存在发送者/接收者的名字或姓氏。

所以,问题是:如何在请求中只提供发送者和接收者的 _id,并将 _id、firstName、lastName 全部保存在交易集合中创建的记录中?

目的:我想创建一个页面,用户可以在其中查看他们最近的交易,因此最好将名称包含在交易集合本身中,否则我将不得不进行单独的数据库调用来获取该名称。

非常感谢您能走到这一步。愿平安与你同在。

mongodb express mongoose mongodb-query mongoose-schema
1个回答
0
投票

您可以修改您的

transactionSchema
,使
sender
receiver
只是键,其值为
ObjectId
,对应于有效的
User._id

const transactionSchema = new mongoose.Schema({
   sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true
   },
   receiver: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true
   },
   amount: {
      type: Number,
      required: true
   }
});

现在,当您创建

Transaction
文档时,您可以简单地执行以下操作:

await TransactionModel.create({ 
   sender: req.body.userId,
   receiver: to,
   amount: amount
});

每当您对

transactions
集合进行查询并且想要获取每个
sender
receiver
文档的详细信息时,您可以使用
populate
,如下所示:

const transaction = await TransactionModel.find()
.populate('sender')
.populate('receiver');

如果您只想要

firstName
lastName
,您可以这样做:

const transaction = await TransactionModel.find()
.populate({path: 'sender', select: 'firstName lastName'})
.populate({path: 'receiver', select: 'firstName lastName'});
© www.soinside.com 2019 - 2024. All rights reserved.