Le garcon
Le garcon

Reputation: 8427

Aggregation: adding fields to mongo document from another object

I have an array which looks like this

const posts = [{ _id: '1', viewsCount: 52 }, ...]

Which corresponds to mongodb documents in posts collection

{
  _id: '1',
  title: 'some title',
  body: '....',
}, ...

I want to perform an aggregation which would result in documents fetched from the posts collection to have a viewsCount field. I'm not sure how I should form my aggregation pipeline:

[
  { $match: {} },
  { $addFields: { viewsCount: ?? } }
]

UPDATE

So far the following code almost does the trick:

[
    { $match: {} },
    { $addFields: { viewsCount: { $arrayElemAt: [posts, { $indexOfArray: [ posts, '$_id' ] } ] } } },
]

But viewsCount in this case turns to be an object, so I guess I need to add $project

UPDATE

I've found out one possible solution which is to use $addFields stage twice - overriding the first viewsCount

[
    { $match: {} },
    { $addFields: { viewsCount: { $arrayElemAt: [posts, { $indexOfArray: [ posts, '$_id' ] } ] } } },
    { $addFields: { viewsCount: '$viewsCount.viewsCount' } }
]

But is there a better/more concise solution?

UPDATE

This pipeline actually works correct:

[
    { $match: {} },
    { $addFields: { viewsCount: { $arrayElemAt: [posts, { $indexOfArray: [ postsIds, '$_id' ] } ] } } },
    { $addFields: { viewsCount: '$viewsCount.viewsCount' } }
]

I have updated the second stage by replacing posts with postsIds

Upvotes: 2

Views: 667

Answers (1)

mickl
mickl

Reputation: 49985

To have a more concise solution (one-stage) you can use $let operator which lets you to define temporary variable that can be then used inside your expression, try:

db.posts.aggregate([
    { $addFields: { 
        viewsCount: {
            $let: {
                vars: { viewsCountObj: { $arrayElemAt: [posts, { $indexOfArray: [ posts, '$_id' ] } ] } },
                in: "$$viewsCountObj.viewsCount"
            }
        } }
    }
])

Upvotes: 2

Related Questions