1

In my example I find the company data that belongs to a user. I then select the board_posts array from within the company which was found. This enables me to get all the posts inside this array. But what I now need to do is only get posts within the board_posts that have an author_id that matches the user_id. Is there a way I can add a filter to select to do this?

router.get('/posts',  passport.authenticate('jwt', { 
    session: false 
}), (req, res) => {
    let user = req.user;
    let user_id = user._id;

    Company.findById(user.company_id)
        .select('board_posts')//filter board_posts if( board_posts.author_id == user_id)
        .then(result => {
            res.status(200).json(result.board_posts);
        })
        .catch(error => {
            console.log(error)
        });
});

Company Schema:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const BoardPostSchema = new Schema({
    name: {
        type: String
    },
    author_id: {
        type: Schema.Types.ObjectId
    }
});

const CompanySchema = new Schema({
    company_name: {
        type: String
    },
    board_posts: [BoardPostSchema],
});

module.exports = Company = mongoose.model('companies', CompanySchema);

This is the result if I remove the select and just console.log the result

{ 
    _id: 5e98255f1c9d440000eefaf5,
    company_name: 'Fyber',
    board_posts:[
        { 
            _id: 5e98500c29a6915d84745879,
            name: 'hello',
            author_id: 5e847e3822a416106c4cb999 
        },
        {
            _id: 5e9852256e455a4814e54d36,
            company_name: 'test',
            author_id: 5e847e3822a416106c4cb999 
        },
        { 
            _id: 5e98532770ea8748c41a6dc1,
            company_name: 'what',
            author_id: 5e847e3822a416106c4cb360 
        },
        { 
            _id: 5e9859b7c41ea60fd4e433ca,
            name: 'another',
            author_id: 5e847e3822a416106c4cb360 
        },
    ] 
}
Reece
  • 2,581
  • 10
  • 42
  • 90

1 Answers1

2

You can do this by using $filter aggregation:

const { ObjectId } = require("mongoose").Types;

router.get("/posts", passport.authenticate("jwt", { session: false }), (req, res) => {
  let user = req.user;
  let user_id = user._id;

  Company.aggregate([
    {
      $match: {
        _id: ObjectId(user.company_id),
      },
    },
    {
      $project: {
        board_posts: {
          $filter: {
            input: "$board_posts",
            as: "item",
            cond: {
              $eq: ["$$item.author_id", ObjectId(user_id)],
            },
          },
        },
      },
    },
  ])
    .then((result) => {
      if (result) {
        res.status(200).json(result[0].board_posts);
      } else {
        res.status(404).json({ msg: "Company Not Found" });
      }
    })
    .catch((error) => {
      console.log(error);
    });
});

Playground

SuleymanSah
  • 17,153
  • 5
  • 33
  • 54
  • I just had to add the result index ```result[0]``` like in your example that fixed my issue. This works perfectly. One question though what do all the dollar signs do? – Reece Apr 16 '20 at 14:30
  • 1
    @Reece $ is reserved for mongodb operators. – SuleymanSah Apr 16 '20 at 14:32