samman adhikari
samman adhikari

Reputation: 651

How to compute the sum of a value from objects inside an array and add a filed based on that sum using mongoose aggregate?

I am in the middle of writing a complex aggregate pipeline in mongoose. I need to sum the views of every article writin my an author and than assign the author that value. The data now looks something like this:

{
  _id: "...",
  authorName: "...",
  artiles: [
    {articleTitle: "...", views: 4},
    {articleTitle: "...", views: 2},
    {articleTitle: "...", views: 10},
  ]
}

The data I want is this:

{
  _id: "...",
  authorName: "...",
  artiles: [
    {articleTitle: "...", views: 4},
    {articleTitle: "...", views: 2},
    {articleTitle: "...", views: 10},
  ],
  totalArticleViews: 16   // 4 + 2 + 10
}

How may I do so using mongoose aggregate pipeline?

The other thing is the articles and views have their own separate model. So in the pipeline what is happing is that I am using $lookup to get all the articles of an author, and inside that $lookup there is another $pipeline that fetches all the views for a particular article.

Author.aggregate([
  {
    $lookup: {
      from: 'articles',
      as: 'articles',
      let: { localFieldValue: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$author", "$$localFieldValue"] } } },
        { $lookup: { from: 'views', localField: '_id', foreignField: 'document', as: 'views' } },
      ]
    }
  }
])

So rather than computing the view count after populating articles and views, It would be better If I could increment the totalViewCount of an author from within the $pipeline that contains the $lookup for views.

Upvotes: 0

Views: 25

Answers (1)

Takis
Takis

Reputation: 8695

Using $reduce you can do it in an easy way.

Test code here

Query

  • reduce the articles array, starting with sum=0 to find the total sum of views
  • add a field in the document with that sum
db.collection.aggregate([
  {
    "$set": {
      "totalArticleViews": {
        "$reduce": {
          "input": "$articles",
          "initialValue": 0,
          "in": {
            "$let": {
              "vars": {
                "tviews": "$$value",
                "article": "$$this"
              },
              "in": {
                "$add": [
                  "$$tviews",
                  "$$article.views"
                ]
              }
            }
          }
        }
      }
    }
  }
])

Upvotes: 1

Related Questions