如何删除MongoDB中的文档和所有嵌入文档?

时间:2015-03-04 08:00:08

标签: javascript node.js mongodb mongoose cascade

我在Mongoose中定义了以下架构:

var postSchema = mongoose.Schema({
  title: String,
  body: String,
  created: Date,
  photos: Array
});

var Post = mongoose.model('Post', postSchema);

var photoSchema = mongoose.Schema({
  filename: String,
  mimetype: String,
  data: Buffer,
  created: Date
});

var Photo = mongoose.model('Photo', photoSchema);

如果我删除了Post,我也希望删除所有相关的Photo(例如SQL中的级联删除)。

如果我执行Post.remove({ _id: MY_POST_ID }),则只会删除Post并且我在数据库中留下了孤儿Photo

另外,我应该以某种方式在Photo架构中定义帖子ID吗?

2 个答案:

答案 0 :(得分:1)

获得真正原子操作的唯一方法是实际使用嵌入式模型:

var photoSchema = mongoose.Schema({
  filename: String,
  mimetype: String,
  data: Buffer,
  created: Date
});

var postSchema = mongoose.Schema({
  title: String,
  body: String,
  created: Date,
  photos: [photoSchema]
});

var Post = mongoose.model('Post', postSchema);

然后你可以用一个简单的语句删除所有内容,因为它们都在同一个集合中,实际上是同一个文档:

Post.remove({ "_id": postId },function(err) {
   // handling in here
});

使用您当前的架构,您需要单独删除所有文档:

var async = require("async");

var photoSchema = mongoose.Schema({
  filename: String,
  mimetype: String,
  data: Buffer,
  created: Date
});

var Photo = mongoose.model('Photo', photoSchema);

var postSchema = mongoose.Schema({
  title: String,
  body: String,
  created: Date,
  photos: [{ "type": Schema.types.ObjectId, "ref": "Photo" }]
});

var Post = mongoose.model('Post', postSchema);

// later

async.waterfall(
    [
        function(callback) {
            Post.findById(postId,callback);
        },

        function(post,callback) {
            Photo.remove({ "_id": { "$in": post.photos } },function(err) {
               if (err) callback(err);
               callback();
            });
        },

        function(callback) {
            Post.remove(photoId,callback);
        }
    ],
    function(err) {
       if (err); // do something
       // Job done
    }
)

如果您想先避免阅读文件,那么

var photoSchema = mongoose.Schema({
  postId: Schema.types.ObjectId,
  filename: String,
  mimetype: String,
  data: Buffer,
  created: Date
});

然后删除与“帖子”相关的所有“照片”,然后发出:

Photo.remove({ "postId": postId },function(err) {
   // removed or err
});

一般来说,如果你总是想要这种行为,并且你的“帖子”文件不能超过16MB并且所有嵌入的“照片”信息,那么嵌入选项最有意义,因为你不需要“照片”除了作为单亲的孩子之外,实际上是在其他任何地方使用。

答案 1 :(得分:0)

如果添加的照片只属于一个Post,则可以将所有照片嵌入Post架构中。您可以通过将照片对象推送到Post架构中的照片数组来实现。然后,您的Post文档将具有以下结构:

{
    title: 'My-first-post',
    body: 'Lorem ipsum',
    created: '01-01-1900',
    photos: [
        { filename: 'file1', mimetype: 'type', data: 238947289347239874, created: '01-02-1900' },
        { filename: 'file2', mimetype: 'type', data: 238947284321225671, created: '02-02-1900' }
    ]
}
相关问题