猫鼬:创建时会自动嵌入字段?

时间:2020-05-28 16:52:29

标签: javascript node.js mongodb mongoose

说我有一个模型Book和另一个模型Genre。创建图书时,我希望能够传递一个Genre ID并让模型自动获取并嵌入文档。例如:

const bookSchema = new Schema({
  title: {
    type: String,
    required: true,
  },
  author: {
    type: String,
    required: true,
  },
  genre: {
    type: ObjectId,
    required: true,
  }
});

const genreSchema = new Schema({
  name: {
    type: String,
    required: true,
  },
});

然后我要制作一本书,如下所示:

const Book = await Book.create({
  title: 'Lord of the Rings',
  author: 'J. R. R. Tolkien',
  genre: '5d6ede6a0ba62570afcedd3a',
});

这将创建一本书,并自动根据给定ID嵌入类型文档。有没有一种方法可以从模式内部完成,还是必须将其包装在其他逻辑中?

4 个答案:

答案 0 :(得分:4)

您可以使用预先保存的猫鼬middleware/hook查找类型,并将其设置为嵌入式文档。在猫鼬预保存钩子中,this将是当前文档,您可以在将该值写入数据库之前读取该值并将其设置为this对象。

请注意,由于这是一个前 save 挂钩,因此它将仅在Model.create()document.save()上运行。因此它将不会在Model.insertMany()上运行。 但是将在您使用document.save()更新文档时运行。如果只想在新文档上设置类型,则必须检查this.isNew属性

const { Schema, Types } = mongoose
const genreSchema = new Schema({
  name: {
    type: String,
    required: true,
  },
});
const Genre = mongoose.model('Genre', genreSchema)

const bookSchema = new Schema({
  title: {
    type: String,
    required: true,
  },
  author: {
    type: String,
    required: true,
  },
  genreId: {
    type: Schema.Types.ObjectId,
    required: true,
  },
  genre: {
    type: genreSchema,
  },
});

bookSchema.pre('save', async function() {
  if (this.isNew) { // this.isNew will be true on only new documents
    this.genre = await Genre.findById(this.genreId) // `this` is the new book document
  }
})

const Book = mongoose.model('Book', bookSchema)

/* Test book creation */
const genre = await Genre.create({
  name: 'Fantasy'
})

const book = await Book.create({
  title: 'Lord of the Rings',
  author: 'J. R. R. Tolkien',
  genreId: genre._id,
});

console.log(book)

答案 1 :(得分:1)

您可以使用混合模式类型和文档中间件来解决您的问题。请参见下面的示例代码:

const genreSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
    },
});

const Genre = mongoose.model('Genre', genreSchema);

const bookSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true,
    },
    author: {
        type: String,
        required: true,
    },
    genre: {
        type: Object,
        required: true,
    }
});
bookSchema.pre('save', async function () {
    const genreID = mongoose.Types.ObjectId(this.genre);
    this.genre = await Genre.findById(genreID);

});

const Book = mongoose.model('Book', bookSchema);
const newBook = new Book({ title: 'The book', author: 'xyz', genre: '5ef55c67be27fb2a08a1131c' });
newBook.save();

答案 2 :(得分:0)

您如何知道要嵌入哪个流派ID?您可以从前端发送此邮件吗?

如果是,则只需从前端选择类型ID,然后将其传递到API的请求正文中即可。

在后端时:

router.route('/book')
    .post((req, res) => {
        Book.create({
            title: req.body.title,
            author: req.body.author,
            genre: req.body.genre,

        }, (err, product) => {
            if (err) {
                res.send(err);
            } else {
                res.json({success:true})
            }
        });
    })

执行类似的操作以在Book集合中创建一个新的book对象。

答案 3 :(得分:-1)

如果我正确理解了您的问题,我认为您正在寻找的是人口。 https://mongoosejs.com/docs/populate.html

它将更改您的架构,使其类似于以下内容

const bookSchema = new Schema({
  title: {
    type: String,
    required: true,
  },
  author: {
    type: String,
    required: true,
  },
  genre: {
    type: Schema.Types.ObjectId,
    ref: 'Genre',
    required: true,
  }
});

const genreSchema = new Schema({
  name: {
    type: String,
    required: true,
  },
});

当您拿到书时,您可以通过这样做来参考类型

Book.find()
  .populate('genre')

希望能回答您的问题!