These are chat archives for Automattic/mongoose

29th
Oct 2016
Paul "Joey" Clark
@joeytwiddle
Oct 29 2016 09:51
@chaconv you also need Promise.all([prom1, prom2, ...]).then(...)
Paul Barrick
@peb7268
Oct 29 2016 12:06
Interesting. Someone else suggested populate. This works better or if that not what populate is for?
Paul Barrick
@peb7268
Oct 29 2016 16:56
@joeytwiddle
Paul "Joey" Clark
@joeytwiddle
Oct 29 2016 17:21

@peb7268 .populate() works if one document contains a ref to the other.
E.g. if a student can have one tutor and many classes:

tutor: {type: Schema.ObjectId, ref: 'teacher'},
classes: [{type: Schema.ObjectId, ref: 'class'}],

then you can do:

Student.find({}).populate('tutor classes')

Use that when possible, I think it is more efficient.

Paul Barrick
@peb7268
Oct 29 2016 18:24
Sweet thanks.
Jarrett Green
@jarrettgreen
Oct 29 2016 22:17
Hey guys. I have a schema question. I'm wanting to build a dynamic dashboard. User can add widgets, etc. basic Models are Dashboard, WidgetFrame, Widget. Dashboard is the containing element that holds a bunch of WidgetFrames, (they hold size, position, etc.), and the Widget which will be some sort of polymorph - a button, a gauge, a line chart, etc. ) Coming from a RDB world, I thought the Mongo way of doing this would to to keep everything as sub docs in in the Dasboard model
But I was confusing myself with my express routes. I can get it all to save, it just feels clunky. to post to api/v1/dashboards/:dashboard_id/widgets and get back a dashboard and all widgets instead of just was created.
Michael Leanos
@mleanos
Oct 29 2016 22:31

@jarrettgreen This is a good question. Something I'm very interested in getting feedback from as well. I've struggled with this aspect of my API design, and it seems very intimately related to my schema's. Should I nest this schema, or should I break it out into it's own collection?

These questions ultimately lead me to asking myself if the schema in question would ever need to exist outside the context of an individual Dashboard (to use your case as an example). If the answer to this is "no", then I can leave it as a nested schema. Obviously, if the answer is "yes", you can move it to it's own collection & you'd have a much easier decision as to how to design your API.

When using a nested a schema, I tend to build my API around the fact that my context is always "Dashboard", and would lean toward having my API api/v1/dashboard/:dashboard_id/add-widget. I'm not sure if this is the most logical choice.

Jarrett Green
@jarrettgreen
Oct 29 2016 22:34
@mleanos That's what my thinking was as well, and thanks for taking the time! These objects will never exist outside of a dashboard. For other CRUD related actions for widgets, would you create similar routes? i.e. /api/v1/dashboard/:dashboard_id/add-widget, api/v1/dashboard/:dashboard_id/update-widget, api/v1/dashboard/:dashboard_id/delete-widget
Or one restful base path that take post, patch, and delete @ /api/v1/dashboard/:dashboard_id/widgets
Michael Leanos
@mleanos
Oct 29 2016 22:37
I guess my question would be how would you specify an individual widget? In the past I've used the _id field of my nested schema and provided that in my route api/v1/dashboard/:dashboard_id/widget/:widget_id for post, delete, and put (patch is probably favorable)
Jarrett Green
@jarrettgreen
Oct 29 2016 22:38
ah right. Yeah by _id. So why the speficially named routed for add-widget?
Michael Leanos
@mleanos
Oct 29 2016 22:43
For simplicity I guess. However, using just a post on .../widgetswould fall in line with the other patterns of my routes better. I've actually interchanged both options, but that was most likely out of laziness or just not caring too much :) Things just get more complex when updating/deleting so I would tend to follow more standardized conventions in that case.
Jarrett Green
@jarrettgreen
Oct 29 2016 22:43
gotcha
For the second part, it feel weird to return the entire dashboard. This is probably my like of experience with mongoose and express et. al. , but I have
export function addDashboardWidget(req, res) {
 Dashboard.findOne({ _id: req.params.dashboard_id }).exec((err, dashboard) => {
    if (err) {
      res.status(500).send(err);
    } else {
      const newDashboardWidget = new DashboardWidget(req.body.dashboardWidget);
      newDashboardWidget.title = sanitizeHtml(newDashboardWidget.title);
      dashboard.dashboardWidgets.push(newDashboardWidget);
      dashboard.save((err, saved) => {
        if (err) {
          res.status(500).send(err);
        }
        res.json({ dashboard: saved });
      });
  }
 });
}
Michael Leanos
@mleanos
Oct 29 2016 22:47
Yup. Struggled with that too. Usually you don't need to send back the whole dashboard. You can just send back the new widget, or it could even be argued that merely sending back a status of 200 is more appropriate.
Jarrett Green
@jarrettgreen
Oct 29 2016 22:48
got ya. Man I appreciate it!
Michael Leanos
@mleanos
Oct 29 2016 22:51
If sending back just a status of 200, this would mean the client would have to push the new widget into the dashboard, which could cause the client to be out of sync with the db for a very minute amount of time or perhaps indefinitely if the client never updated the dashboard or lost connection with the server. However, I think that might be an edge case and mostly the fault of the client or connectivity.
Jarrett Green
@jarrettgreen
Oct 29 2016 22:51
I've got redux on the client side, I think ack'ing a 200 would be enough
Michael Leanos
@mleanos
Oct 29 2016 22:53
BTW, you could use findOneAndUpdate with the $push method. Would save one db call.
And sure, no worries.. I'm interestd in this topic. Would love to hear from others.
Jarrett Green
@jarrettgreen
Oct 29 2016 22:58
that sounds great - do you a ref to those docs? I can't seen to find it on mongoosejs.com
Michael Leanos
@mleanos
Oct 29 2016 23:00
findOneAndUpdate uses the same operators as update: https://docs.mongodb.com/manual/reference/operator/update/#id1