0

i have this Schema for a simple twitter app

const userSchema = new Schema ({
    loginInfo: {
        username: String,
        email: String,
        password: String 
    },
    tweets: [{
        content: String,
        likes: Number,
        comments: [{
            owner: String,
            content: String,
            likes: Number
        }]
    }],
    followers: [String],
    following: [String]
})

and i want to make endpoint that return only the tweet that has the same _id that has been given as a params on the URL .. I made that solution below and its working correctly but i believe there is a much better solution than this ..

const handleTweet = (User) => (req,res) => {
    const { id } = req.params;
    let theTweet = [];
    User.findOne({ "tweets._id": id})
    .then(user => {
        user.tweets.forEach(tweet => {
            if(tweet._id.toString() === id)
                return theTweet.push(tweet)
        })
        res.json(theTweet)
    })
    .catch(err => res.json(err))
}

module.exports = handleTweet;

One more question : Is it better to make nested schemas like this or making a different models for each schema (in this case schema for User and another one for Tweets) ?

2 Answers2

1

You should make the tweets into a different collection since you are querying based on that, and then you can use autopopulate when you need it.

Also instead of the foreach you could use Array.prototype.find

Hope this helps!

Community
  • 1
  • 1
Balázs Zákány
  • 407
  • 2
  • 11
1

You can use the $push & findOneAndUpdate methods from mongoose. You can modify your example to be like this:

User.findOneAndUpdate(id, { $push: { tweets: req.body.tweet } }, {new: true})
    .then((record) => {
      res.status(200).send(record);
    })
    .catch(() => {
      throw new Error("An error occurred");
    });

Notice the {new: true} option, it makes the findOneAndUpdate method to return the record with the edit.

For your second question, it's recommended to split the modals to make your code more readable, maintainable and easy to understand.

mohamed saad
  • 75
  • 2
  • 9
  • Sorry to disappoint you , but the question was how to grab an existing tweet not how to add new one xD for the second question, okay i will make 2 models but how to reference them by id for example ? – Esmail Elmoussel Mar 27 '20 at 21:23
  • Ah, Sorry for that, consider using `find` instead of `forEach`. Also as u search by id, you don't have to make an array and send it in the response as it's and will always be one element with this id. So `find` instead of `forEach` then send that element (not the array). – mohamed saad Mar 27 '20 at 21:49
  • 1
    For your second question, there's a lot of other solutions. First one by splitting into 2 schemas and use `populate` (check this [answer](https://stackoverflow.com/a/29079951/10005777) ) , Second one by making your schema like this: ```js const userSchema = new Schema ({ username: String, email: String, password: String, tweets: [{ content: String, likes: Number, comments: [{ owner: String, content: String, likes: Number }] }], followers: [String], following: [String] }) ``` – mohamed saad Mar 27 '20 at 21:57
  • There's third solution which is by adding `authorId` field to the tweet schema and save the creator id with the tweet. – mohamed saad Mar 27 '20 at 21:59