Reputation: 723
I have the following schema defined in 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);
If I remove a Post
, I'd like all the related Photo
s to be removed as well (like cascading delete in SQL).
If I do Post.remove({ _id: MY_POST_ID })
, only the Post
gets removed and I have orphan Photo
s left in the database.
Also, should I somehow define the post ID in the Photo
schema?
Upvotes: 0
Views: 1269
Reputation: 151072
The only way you get a truly atomic operation is to actually use an embedded model like so:
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);
Then you can actually remove everything with one simple statement since it is all in the same collection and indeed the same document:
Post.remove({ "_id": postId },function(err) {
// handling in here
});
With your current schema you would need to remove all documents individually:
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
}
)
If you want to avoid reading the document first then you
var photoSchema = mongoose.Schema({
postId: Schema.types.ObjectId,
filename: String,
mimetype: String,
data: Buffer,
created: Date
});
Then to remove all "photos" related to a "post" then you issue:
Photo.remove({ "postId": postId },function(err) {
// removed or err
});
Generally speaking, if you always want this behavior and your "post" document cannot grow beyond 16MB with all the embedded "photo" information then the embedding option makes the most sense since you then don't require that a "photo" is actually used anywhere else than as a child of a single parent.
Upvotes: 1
Reputation: 5908
If added photos only belong to one Post
, you can embed all the photos in the Post
schema. You can do so by pushing photo objects to the photos array in the Post
schema. Then, your Post
documents would have the following structure:
{
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' }
]
}
Upvotes: 0