简体   繁体   中英

How to push an element into an array inside an object inside another array in Mongoose?

I am developing a server using Expressjs, Mongodb and Mongoose. I need to push an element (a string) into the "tweets" array which is inside an object (a friend) which is in turn inside the "friends" array which is inside a "user" Object which document in the "users" collection. Here is an example of how my documents in the Mongodb collection looks like:

{
    "loggedIn": true,
    "_id": "5f91ef0ce75d3b1d40539da0",
    "username": "username",
    "email": "a@h.com",
    "password": "$2a$10$9krWS9Kq5024lRTexqaweePrn8aughepqTkaj3oA48x0fJ2ajd79u",
    "dateOfBirth": "2002-12-07",
    "gender": "male",
    "friends": [
        {
            "tweets": [],
            "_id": "5f91effae75d3b1d40539da7",
            "username": "Jonas"
        },
        
    ],
    "__v": 0
}

I need to pick the specified username from the "Users" arrary first and then access "friends" array within this user and then pick the right friend object and finally push the tweet on $position: 0 in this array. II tried to achieve that as shown in this code and I could access the friend object with the given friendUsername

await Users.updateOne(
      { username: req.params.username },
      {
        $push: {
          friends: {
            $elemMatch: {
              username: req.params.friendUsername,
            },
          },
        },
      }
    );

And now the question is how to access the "tweets" array inside $elemMatch and push the req.body.tweet at $position: 0 into it?

Here is how I would solve your issue, I first would re-define the way I am defining schemas.

My User schema would look something like the following

User.js

const mongoose = require('mongoose')

const UserSchema = mongoose.Schema({
 ...
 friends: {
    type: [{
       type: mongoose.Schema.Types.ObjectId,
       ref: 'User'
    }],
    required: true,
    default: []
  },
  tweets: {
    type: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Tweet'
    }],
    required: true,
    default: []
  },
 ...
}, {timestamps: true})

module.exports = mongoose.model('User', UserSchema)

User.js

const mongoose = require('mongoose')

const TweetSchema = mongoose.Schema({
 ...
 text: {
    type: String,
    required: true
  },
 tweeter: {
    type: mongoose.Schema.Types.ObjectId,
    required: true,
    ref: 'User'
 },
 likes: {
    type: [{
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User'
    }],
    required: true,
    default: []
  },
 ...
}, {timestamps: true})

module.exports = mongoose.model('Tweet', TweetSchema)

This assumes that every user can have tweets and that a User can be friend with another User

And now if someone tweets something you can do something like

const Tweet = require('./Tweet.js')
const User = require('./User.js')

let tweet = new Tweet({
    text: "My first tweet!",
    tweeter: "ID Of user who is posting the tweet"
})

tweet.save()

// Now update the user who tweeted
User.findOneAndUpdate()
User.updateOne({ _id: "ID Of user who is posting the tweet" }, { $push: { tweets: tweet._id } })

and now whenever you request a user all of his friends will be referenced and all of their tweets will also be referenced! if you want to see the actual tweets then use something like .populate() here are the docs for .populate() https://mongoosejs.com/docs/populate.html

Keep in mind is really a good practice to only return the actual ids and your frontend takes care of requesting the appropriate objects from their perspective endpoints. And if you wish to reduce.network calls then the frontend would cache the data.

If the above doesn't help and you still would like to achieve your goal with your schemas then something like this should work (assuming your schema is called User )

let tweetObj = {}
User.updateOne({_id: 'your userid'}, {$push: {"friends.$.tweets": tweetObj}})

NOTE: I have omitted callbacks as they are irrelevant to the question

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM