2

I am currently in the process of modifying a schema and I need to do a relatively trivial transform using the aggregation framework and a bulkWrite.

I want to be able to take this array:

{ 
     ...,
     "images" : [
        "http://example.com/...", 
        "http://example.com/...", 
        "http://example.com/..."
    ] 
}

and aggregate to a similar array where the original value is encapsulated:

{ 
     ...,
     "images" : [
        {url: "http://example.com/..."}, 
        {url: "http://example.com/..."}, 
        {url: "http://example.com/..."}
    ] 
}

This slow query works, but it is ridiculously expensive to unwind an entire collection.

[
    {
        $match: {}
    },
    {
        $unwind: {
            path : "$images",
        }
    },
    {
        $group: {
            _id: "$_id",
            images_2: {$addToSet: {url: "$images"}}
        }
    },
]

How can this be achieved with project or some other cheaper aggregation?

2 Answers 2

3

$map expression should do the job, try this:

db.col.aggregate([
  {
    $project: {
      images: {
        $map: {
          input: '$images',
          as: 'url',
          in: {
            url: '$$url'
          }
        }
      }
    }
  }
]);
Sign up to request clarification or add additional context in comments.

Comments

1

You don't need to use the bulkWrite() method for this.

You can use the $map aggregation array operator to apply an expression to each element element in your array.

Here, the expression simply create a new object where the value is the item in the array.

let mapExpr = {
    "$map": {
        "input": "$images",
        "as": "imageUrl",
        "in": { "url": "$$imageUrl }
    }
};

Finally you can use the $out aggregation pipeline operator to overwrite your collection or write the result into a different collection.

Of course $map is not an aggregation pipeline operator so which means that the $map expression must be use in a pipeline stage.

The way you do this depends on your MongoDB version.

The best way is in MongoDB 3.4 using $addFields to change the value of the "images" field in your document.

db.collection.aggregate([
    { "$addFields": { "images": mapExpr }},
    { "$out": "collection }
])

From MongoDB 3.2 backwards, you need to use the $project pipeline stage but you also need to include all the other fields manually in your document

db.collection.aggregate([
    { "$project": { "images": mapExpr } },
    { "$out": "collection }
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.