Saral Shrivastava
Saral Shrivastava

Reputation: 23

How to write mongoose query to combine data from two model's?

Technology: MongoDB, ExpressJS

I have 3 schema

  1. userSchema:
userSchema = {
  name: {type: String},
  password: {type: String},
  email: {type: String},
  friends: {type: [mongoose.Types.ObjectId]}
}
  1. textPostSchema =
textPostSchema = {
   text: {type: String},
   postType: {type: String, default: "textPost"},
   userId: {type: mongoose.Types.ObjectId}
}
  1. articalPostSchema:
articalPostSchema = {
  title: {type: String},
  content: {type: String}
  postType: {type: String, default: "articalPost"},
  userId: {type: mongoose.Types.ObjectId}
}

now I have one social media application in which I have to show these two post when user's friend post's a post, and include infinite scroll. Both textPost and articalPost should be send if to frontend and only total 10 post should be sent at a time. How should I write a API for timeline?

output should look like:

{
  post: [
          {
           title: "artical Post title", 
           content: "artical post content", 
           postType: "articalPost", 
           userId: "60b9c9801a2a2547de643ccd"
          },
          {
           text: "text post ", 
           postType: "textPost", 
           userId: "60b9c9801a2a2547de643ccd"
          }, 
          ... 8 more
        ]
}

UPDATE: I got the solution:- I created on more schema:

timelineSchema = {
    postId: {
      type: mongoose.Types.ObjectId,
      required: true,
      ref: function () {
        switch (this.postCategoryType) {
          case 'articleposts':
            return 'ArticlePost';
          case 'textposts':
            return 'TextPost';
        }
      },
    },
    postCategoryType: {
      type: String,
      required: true,
    },
    userId: {
      type: mongoose.Types.ObjectId,
      required: true,
      ref: 'User',
    },
  },

and then I created one function to get only friends post:

exports.getTimelinePosts = async (req, res) => {
  try {
    const timelinePosts = await TimelineModel.find({
      userId: { $in: [...req.user.friends, req.params.id] },
    })
      .skip((req.params.page - 1) * 10)
      .limit(10)
      .sort({ createdAt: -1 })
      .populate('postId');
    return res.status(200).json({ status: 'success', data: timelinePosts });
  } catch (error) {
    return res.status(500).json(error);
  }
};

Upvotes: 2

Views: 508

Answers (2)

Uddesh Jain
Uddesh Jain

Reputation: 1104

To implement the pagination with Mongoose, You can do something like that.

const getPosts = async (userId, pageNumber) => {
  let result = await Post.find({ userId })
    .skip((pageNumber - 1) * 10)
    .limit(10);

  return result;
};

pageNumber is a counter that you need to pass from the frontend and will be incremented by 1 whenever a user hits the scroll limit.

If you want to query and merge data from multiple collections you need to update your schema to use populate. Just include ref where you are referring to other collections.

This may help. https://mongoosejs.com/docs/populate.html

Upvotes: 1

Abu Sayeed Mondal
Abu Sayeed Mondal

Reputation: 455

Assuming you are using express and mongoose. The code to fetch both,

// first bring all those schema from your mongoose models
const Article = require('./models/ArticleSchema');
const Text = require('./models/TextSchema');

const fetchArticleAndTextPost = async (req, res)=>{
    //find all data 
    const articles = await Article.find();
    const texts = await Text.find();

    //join them together
    const post = articles.concat(texts);

    return res.status(200).json({
        status: 200,
        data: post,
    })

}

Upvotes: 1

Related Questions