6

I'm trying to delete multiple documents that satisfy a query. However I need the data of those documents for storing them in a separate collection for undo functionality. The only way I got this to work is with multiple queries:

Data.find(query).exec(function(err, data)
{
    Data.remove(query).exec(function(err2)
    {
        ActionCtrl.saveRemove(data);
    });
});

Is there a better way? In this post: How do I remove documents using Node.js Mongoose? it was suggested to use find().remove().exec():

Data.find(query).remove().exec(function(err, data)
{
    ActionCtrl.saveRemove(data);
});

However data is usually 1, don't ask me why. Can I do this without infinitely nesting my queries? Thanks!

Community
  • 1
  • 1
Micha Schwab
  • 786
  • 1
  • 6
  • 21
  • Out of curiosity why not use a document property to indicate if it's been "deleted"? – Jason Cust Jul 28 '15 at 02:04
  • Partly: http://richarddingwall.name/2009/11/20/the-trouble-with-soft-delete/ Also: 1 delete command might trigger removal of several connected documents, and i want those to be restored as well if the command is undone. im using a modified memento pattern that works for multiple documents for this. – Micha Schwab Jul 28 '15 at 02:26
  • 1
    You could use Mongoose's [discriminators](http://mongoosejs.com/docs/api.html#model_Model.discriminator) instead. It allows two document schemas (inherited from a common base schema) to be stored in the same collection. – Jason Cust Jul 28 '15 at 03:49

1 Answers1

3

As you have noted, using the following will not return the document:

Data.find(query).remove().exec(function(err, data) {
  // data will equal the number of docs removed, not the document itself
}

As such, you can't save the document in ActionCtrl using this approach.

You can achieve the same result using your original approach, or use some form of iteration. A control flow library like async might come in handy to handle the async calls. It won't reduce your code, but will reduce the queries. See example:

Data.find(query, function(err, data) {
  async.each(data, function(dataItem, callback) {
    dataItem.remove(function(err, result) {
      ActionCtrl.saveRemove(result, callback);
    });
  });
});

This answer assumes that the ActionCtrl.saveRemove() implementation can take an individual doc as a parameter, and can execute the callback from the async.each loop. async.each requires a callback to be run without arguments at the end of each iteration, so you would ideally run this at the end of .saveRemove()

Note that the remove method on an individual document will actually return the document that has been removed.

snozza
  • 2,123
  • 14
  • 17
  • Would doing the first approach return an error if the `find(query)` returns an empty array? Or would `data` indicate that nothing has been deleted? – Aaroh Mankad Sep 01 '17 at 18:45