ga-wdi-boston / capstone-project

Other
3 stars 29 forks source link

Nesting Like Schema in Run Model #860

Closed jbculbertson closed 6 years ago

jbculbertson commented 6 years ago

I have a Like schema successfully nested within my Run schema. When I create a new Like, my Run is updated. Currently, the only attribute being assigned to a like is an ID. I'd also like to assign an attribute of ownerName, and I think I can have my Like create controller action assign this from req.user.

In testing, when I create a Like, when I Object.assign, it has the fullName attribute. But when I run.update, it doesn't seem to send it with, and I can't tell from the controller why not.

Here is my Like create controller action.

const create = (req, res, next) => {
  console.log('req.user is ', req.user)
  console.log('req.body is ', req.body.like)
  const like = Object.assign(req.body.like, {
    // _owner: req.user._id,
    _ownerFullName: req.user.fullName
  })
  console.log('after object.assign, like is: ', like)
  Run.update(
    { _id: req.body.like._run_id },
    { $push: { likes: like } }
  )
  .then(data => {
    console.log('after run.update, data is: ', data)
    return data
  })
    .then((like) => res.sendStatus(204))
    .catch(next)
}

Here is my Like schema

const likeSchema = new mongoose.Schema({
  _owner: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  _ownerFullName: {
    type: String,
    required: true
  },
  _run_id: {
    type: String,
    required: true
  }
}, {
  timestamps: true,
  toJSON: {
    virtuals: true,
    transform: function (doc, ret, options) {
      const userId = (options.user && options.user._id) || false
      ret.editable = userId && userId.equals(doc._owner)
      return ret
    }
  }
})
jbculbertson commented 6 years ago

and for good measure my Run schema

'use strict'

const mongoose = require('mongoose')

const runSchema = new mongoose.Schema({
  distance: {
    type: Number,
    required: true
  },
  date: {
    type: Date,
    required: true,
    default: Date.now
  },
  timeTaken: {
    type: Number,
    required: true
  },
  route: {
    type: [[Number]],
    required: true
  },
  likes: {
    type: [{
      like_id: mongoose.Schema.Types.ObjectId
    }],
    ref: 'Like'
  },
  _owner: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  _ownerFirstName: {
    type: String,
    required: true
  },
  _ownerLastName: {
    type: String,
    required: true
  }
}, {
  timestamps: true,
  toJSON: {
    virtuals: true,
    transform: function (doc, ret, options) {
      const userId = (options.user && options.user._id) || false
      ret.editable = userId && userId.equals(doc._owner)
      return ret
    }
  }
})

runSchema.virtual('avgPace').get(function () {
  return +(this.timeTaken / this.distance).toFixed(2)
})

runSchema.virtual('ownerName').get(function () {
  return (this._ownerFirstName + ' ' + this._ownerLastName)
})

const Run = mongoose.model('Run', runSchema)

module.exports = Run
jbculbertson commented 6 years ago

and User schema

'use strict'

const bcrypt = require('bcrypt')
const mongoose = require('mongoose')
const uniqueValidator = require('mongoose-unique-validator')

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true,
    required: true
  },
  firstName: {
    type: String,
    required: true
  },
  lastName: {
    type: String,
    required: true
  },
  token: {
    type: String,
    required: true
  },
  passwordDigest: String
}, {
  timestamps: true,
  toJSON: {
    virtuals: true,
    transform: function (doc, pojoUser) {
      // remove sensitive data from every user document
      delete pojoUser.token
      delete pojoUser.passwordDigest
      return pojoUser
    }
  },
  toObject: {
    virtuals: true
  }
})

userSchema.plugin(uniqueValidator)

userSchema.methods.comparePassword = function (password) {
  const _this = this

  return new Promise((resolve, reject) =>
    bcrypt.compare(password, _this.passwordDigest, (err, data) =>
        err ? reject(err) : data ? resolve(data) : reject(new Error('Not Authorized')))
    ).then(() => _this)
}

userSchema.virtual('password').set(function (password) {
  this._password = password
})

userSchema.virtual('fullName').get(function () {
  return this.firstName + ' ' + this.lastName
})
jordanallain commented 6 years ago

you have Like owned by a User correct?

jbculbertson commented 6 years ago

correct

jordanallain commented 6 years ago

but you are having trouble accessing the ID?

jbculbertson commented 6 years ago

Chris helped me to actually create a Like within my controller, which it wasn't doing before.

I'm still in a similar position though, where the Like I am creating is not the same as the Like I object.assigned a few lines above.

jbculbertson commented 6 years ago

correction, I am correctly creating a like. The like that I am pushing to the Run.likes array is just the ID, not the full object

payne-chris-r commented 6 years ago

Yeah, if you want the full object you need to go get it based on the ID.

jbculbertson commented 6 years ago

Sorry for the delay - I actually got it working by changing my Run schema from:

  likes: {
    type: [{
      like_id: mongoose.Schema.Types.ObjectId
    }],
    ref: 'Like'
  },

to

  likes: [{  }],

Now, within a run, I'm able to see all the attriubutes of a Like! Although it feels weird that I removed it as a reference...

scottyscripts commented 6 years ago

check out this from the mongoose docs http://mongoosejs.com/docs/subdocs.html In this case it's suggesting doing likes: [likeSchema]