Romeo Mihalcea
Romeo Mihalcea

Reputation: 10242

Mongodb delete documents without associated documents

Yeah the title may sound silly but I have two collections: Visitors and Chats. Chat has a visitor while visitor has many chats. Periodically I delete visitors that have a last_activity field lower that x days but I wouldn't wanna delete a visitor who has chat(s) so I need a way to delete from visitors where last_activity < days_unix_milliseconds and _id not in(select visitor_id from chats)

I have a working code for the first part (last activity), need help with the 2nd:

Visitors.remove({
    last_update: {
        $lt: (new Date()).getTime() - 3600000 * 24 * 7
    }
}, function(error){

});

Upvotes: 0

Views: 104

Answers (2)

drmirror
drmirror

Reputation: 3760

So each chat has a field visitor_id and you want to delete only visitors whose _id does not appear as a visitor_id in a chat? You would have to loop over all visitors, check last_activity for each, and if it is a candidate for deletion, do a find() on chats with that visitor's _id. If it turns up no documents, you can delete that visitor.

When you iterate over all visitors, you do that with a MongoDB cursor (the result of a find()). The cursor is implemented in such a way that you can safely delete documents from the underlying collection while iterating over it.

The trick is that you don't attempt to express everything in a single remove() call. You iterate, check, and delete as part of the iteration. You want to make sure that the find() inside the loop is very fast, by adding an index on visitor_id to the chats collection.

Upvotes: 2

Derick
Derick

Reputation: 36774

My advice would be to change your schema so that you can do this with just one query. In this case, I would probably just keep a field with each visitor that tells you how many chats it has. You can simple increase this each time a user starts a chat with:

db.visitors.update( { visitor_id: XXX }, { $inc: { 'chat_count': 1 }  } );

And when it ends:

db.visitors.update( { visitor_id: XXX }, { $inc: { 'chat_count': -1 }  } );

And then removing all visitors that don't have a chat is as simple as:

db.visitors.remove( { last_activity: { $lt: XXX }, chat_count: { $lt: 1 } } );

Upvotes: 6

Related Questions