user320587
user320587

Reputation: 1367

Duplicate elements in a mongo db collection

Is there an quick efficient way to duplicate elements in a mongo db collections based on a property. In the example below, I am trying to duplicate the elements based on a jobId. I am using Spring boot, so any example using Spring boot API would be even more helpful.

Original Collection

{ _id: 1, jobId: 1, product: "A"},
{ _id: 2, jobId: 1, product: "B"},
{ _id: 3, jobId: 1, product: "C"},

After duplication

{ _id: 1, jobId: 1, product: "A"},
{ _id: 2, jobId: 1, product: "B"},
{ _id: 3, jobId: 1, product: "C"},
{ _id: 4, jobId: 2, product: "A"},
{ _id: 5, jobId: 2, product: "B"},
{ _id: 6, jobId: 2, product: "C"},

Upvotes: 0

Views: 469

Answers (1)

mickl
mickl

Reputation: 49945

You can use following aggregation:

db.col.aggregate([
    {
        $group: {
            _id: null,
            values: { $push: "$$ROOT" }
        }
    },
    {
        $addFields: {
            size: { $size: "$values" },
            range: { $range: [ 0, 3 ] }
        }
    },
    {
        $unwind: "$range"
    },
    {
        $unwind: "$values"
    },
    {
        $project: {
            _id: { $add: [ "$values._id", { $multiply: [ "$range", "$size" ] } ] },
            jobId: { $add: [ "$values.jobId", "$range" ] },
            product: "$values.product",
        }
    },
    {
        $sort: {
            _id: 1
        }
    },
    {
        $out: "outCollection"
    }
])

The algorithm is quite simple here: we want to iterate over two sets:

  • first one defined by all items from your source collection (that's why I'm grouping by null)
  • second one defined artificially by $range operator. It will define how many times we want to multiply our collection (3 times in this example)

Double unwind generates as much documents as we need. Then the formula for each _id is following: _id = _id + range * size. Last step is just to redirect the aggregation output to your collection.

Upvotes: 1

Related Questions