3

I have an document structure like this:

_id: 123,
posts: [
   {
      _id: 234,
      likesUser: [345, 456, 567, 678]
   }
]

I want to use $reduce here so my expected output should look like this:

   output: {
      likes: [23, 31, 12, 32],  //each element is the size of the "likesUser" array
      ids: ["14312", "2342", "2312", "235234"]  //each element is the "_id" in the posts array
   }

I have try it like this:

  let result = await Post.aggregate([
    {
      $match: {
        _id: USER
      }
    },
    {
      $project: {
        posts: {
          $reduce: {
            input: "$posts",
            initialValue: { likes: [], ids: [] },
            in: {
              likes: {
                $push: { $size: "$$this.likesUser" }
              },
              ids: {
                $push: "$$this._id"
              }
            }
          }
        }
      }
    }
  ]);

In my frontend i use chart.js. The yAxsis are the likes and the xAxsis are the ID's. So for every element in my posts array i need the length of likesUser and _id But it doenst work. Has anybody an idea how to achive this?

2 Answers 2

6

You are very close, you just have a minor syntax error in your $reduce, Try this:

let result = await Post.aggregate([
    {
        $match: {
            _id: USER
        }
    },
    {
        $project: {
            posts: {
                $reduce: {
                    input: "$posts",
                    initialValue: {likes: [], ids: []},
                    in: {
                        likes: {
                            $concatArrays: ["$$value.likes", [{$size: "$$this.likesUser"}]]
                        },
                        ids: {
                            $concatArrays: ["$$value.ids", ["$$this._id"]]
                        }
                    }
                }
            }
        }
    }
]);
Sign up to request clarification or add additional context in comments.

Comments

1

You are on the right way. You need to use $mergeObjects operator to achieve this. Following query will be helpful:

db.collection.aggregate([
  {
    $match: {
      _id: USER
    }
  },
  {
    $project: {
      post: {
        $reduce: {
          input: "$posts",
          initialValue: {
            likes: [],
            ids: []
          },
          in: {
            $mergeObjects: [
              "$$value",
              {
                likes: {
                  $concatArrays: [
                    "$$value.likes",
                    [
                      {
                        $size: "$$this.likesUser"
                      }
                    ]
                  ]
                },
                ids: {
                  $concatArrays: [
                    "$$value.ids",
                    [
                      "$$this._id"
                    ]
                  ]
                }
              }
            ]
          }
        }
      }
    }
  }
])

MongoPlayGroundLink

I hope the above is helpful.

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.