How to move documents in mongodb between collections

Viewed 41

How can I move one existing document from one collection to another?

Basically, what I have, is a customer Schema:

const customerSchema = new mongoose.Schema ({
    firstname: String,
    lastname: String,
    email: String,
});

and the Model for it:

const Customer = new mongoose.model('Customer', customerSchema);

Now I want to move one document to an archive collection. So I thought, I create a new model, like so:

const CustomerArchive = new mongoose.model('CustomerArchive', customerSchema);

Then, when someone clicks on a Button with the formaction: "/archive-data", the dataset needs to be moved from the Customer collection to the CustomerArchive collection.

  {
    _id: new ObjectId("6325ba96f228119e479963ca"),
    firstname: 'Testuser',
    lastname: 'Testuser',
    email: 'test@user',
    __v: 0
  }

Is there a way to move that one document to another collection without defining each attribute again?

app.post("/archive-data", (req, res) => {
    const docId = req.body.archiveButton;

    Customer.find({ _id: docId }, (err, document) => {
        CustomerArchive.create([document])
    })

})

This is what I have so far, it does work, but there has to be better way - even when it comes to unique IDs or duplicates:

app.post("/archive-data", (req, res) => {
    const docId = req.body.archiveButton;

    Customer.find({ _id: docId}, (err, document) => {
        CustomerArchive.create({
            _id: document[0]._id,
            firstname: document[0].firstname,
            lastname: document[0].lastname,
            email: document[0].email
        });
        Customer.findByIdAndRemove(docId, (err) => {
            if (!err) {
                res.redirect("/customers");
            } else {
                console.log(err);
            }
        });
    })
});

When doing this another problem might arise. Let's assume I move a document from Customer collection to an archive collection. But what, if someone decides to move the archived document back to the Customer collection - the chances that the id already exists might be very low, but within a huge customer db it might happen.

1 Answers

You can simply write a short aggregation pipeline like this:

app.post("/archive-data", async (req, res) => {
    const docId = req.body.archiveButton;

    await Customer.aggregate([
     { $match: 
       { _id: docId}
     }, 
     {
       $merge: {
          into: "customerArchive",
          on: "_id",
          whenMatched: "replace",
          whenNotMatched: "insert"
       }
     }
     ]).exec((err, res) => console.log(`${err} ${res}`));
    Customer.findByIdAndRemove(docId, (err) => {
            if (!err) {
                res.redirect("/customers");
            } else {
                console.log(err);
            }
    });
});

In the pipeline, we first match the required document and merge it into the customerArchive collection using $merge.

If you are using ObjectId, as recommended by Mongodb, you can be sure that it will be unique across collections, as it is a combination of timestamp, a random number, and an auto-incrementing counter, hence the chances of collisions are highly unlikely.

Also, creating a new collection to store just archive customers, seems like overkill, you can reduce a lot of effort, by just storing a boolean value archive in the customer's collections itself, denoting whether the customer is archived or not.

Related