MongoDB找到嵌套查询来填充对象

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

我正在使用mongoose构建一个node.js应用程序,但我现在正试图正确地查询MongoDB ...

我目前有3个MongoDB模型:

Room: {_id, name}
Row: {_id, roomid, name}
Seat: {_id rowid, position, number, status}

1个房间有很多排,1排有很多座位。

我可以使用以下查询获取包含所有行的Room对象:

Room.findOne({ name: req.params.room_name }, { __v: 0 })
  .then(room => {
    room = room.toObject();
    Row.find({ room: new ObjectId(room._id) }, { room: 0, __v: 0 })
      .sort({ name: 1 })
      .then(rows => {
        // current code, not working
        // rows.foreach(row => {
        //   row = row.toObject();
        //   Seat.find({row: new OBjectId(row._id)})
        //     .sort({position: 1})
        //     .then(seats => {
        //       row.seats = seats;
        //     })
        //     .catch(err => console.log(err));
        res.json(room);
      })
      .catch(err => console.log(err));
  })
  .catch(err => {
    console.log(err);
    res.status(500).json(err);
  });

但是,我无法找到获取每一行座位的解决方案,异步处理在每次尝试时都会破坏我的逻辑。我只尝试了一个for循环,async.waterfall(),Promise.all(),但我每次都失败了。

有人帮忙帮我吗?谢谢!

备注:正如评论和可能的答案所建议的那样,我应该只使用一种模式,我已经有了,但我在更新多个席位时遇到了问题。将进一步研究。

node.js mongodb
1个回答
0
投票

通过正确设置引用ref并稍微修改模型,您可以更轻松地实现此目的。但是,我将修改您的代码以向您展示如何按照您的方法执行此操作,然后我将在引用的字段上提供mongoose填充的示例:

Your approach with a plain schema

在进入代码之前,我将用.toObject()替换文件上的.lean()调用,这是一种mongoose方法,在查询文档并优化查询之后为你完成,因为它跳过了将MongoDB原始文档转换为Mongoose对象的过程:

// Encapsulate this with try-catch
const room = await Room.findOne({ name: req.params.room_name }, { __v: 0 }).lean().exec()
const rows = await Row.find({ roomid: room._id }, { roomid: 0, __v: 0 }).lean().exec()

// This is a blocking loop
for (let row of rows) {
    const seats = await Seat.find({ rowid: row._id }, { rowid:0, __v: 0 }).lean().exec()
    row.seats = seats
}

room.rows = rows
res.json(room)
// Close try-catch

现在可以使用Promise.all()稍微优化for循环,await Promises.all(rows.map(async (row) => { const seats = await Seat.find({ rowid: row._id }, { rowid:0, __v: 0 }).lean().exec() row.seats = seats }) 将异步执行每个循环迭代:

const roomModel = mongoose.model('Room', new mongoose.Schema({
    name: String,
    rows: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Row'
    }]
))

Mongoose population approach

让我们通过遵循自然而然地直接向您推荐的推理重新定义您的模型:

1个房间有很多行

然后你可以期望你的房间有一系列行ID,如下所示:

Room.model

const rowModel = mongoose.model('Row', new mongoose.Schema({
    seats: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Seat'
    }],
    name: String
))

进一步,

1排有很多座位

Row.model

const seatModel = mongoose.model('Seat', new mongoose.Schema({
    position: Number,
    number: Number
))

最后你的座椅模型就像下面这样简单:

Seat.model

const room = await Room.findOne({ name: req.params.room_name }, { __v: 0 })
    .populate({
        path: 'rows',
        select: '-__v', // Remove __v field
        populate: {
            path: 'seats',
            select: '-__v' // Remove __v field
    }).lean().exec()

res.json(room)

现在查询更简单:

Neill Lunn

如您所见,遵循此方法并正确设计数据模型更为简单。但是,正如mongoose.model('Room', new mongoose.Schema({ name: String, rows: [{ name: String, seats: [{ position: Number, number: Number, }] }) 在评论中所述,这还不是您期望在MongoDB中设计数据模型的方式。不像你那样定义3个简单的数据模型,最好只为行和席位模式定义带有嵌入式子文档数组的1个模型。与此类似的东西:

Room.model

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.