These are chat archives for Automattic/mongoose

20th
Apr 2018
klequis
@klequis
Apr 20 2018 00:01

I'm just getting started with MongoDB & Mongoose. Have a SQL background

I have a Members document

- _id
- name
- email
- roles [
    {
      roleId: 5ad75bac53f3405c05225ab7
      canFillRole: false
    },
    {
      roleId: 5ad75dcd53f3405c05225ab8
      canFillRole: false
    }
    ... up to 7 possible roles
  ]

Every member will have 0 to 7 roles.
I have the roles in a Roles doc

[
  {
    - _id: 5ad75bac53f3405c05225ab7
    - roleName: Photographer
  },
  {
    - roleId: 5ad75dcd53f3405c05225ab8
    - roleName: News Letter
  }
]

There are currently 7 roles. Roles can be occasionally added or remove.

How to I populate the roles array in Members? Should I use a ref: or is there a better method?

Thank you!

niluroy
@niluroy
Apr 20 2018 05:45
thanks @lineus @panigrah now i am getting the correct result
Kev
@lineus
Apr 20 2018 09:19
happy to help @niluroy :)
Kev
@lineus
Apr 20 2018 09:27
@niluroy now that you've got the async/babel stuff sorted out, you might want to consider changing the way you get the message docs. Instead of running a query for each message id, you can run a single query like Messages.find({ _id: { $in: arrayOfIds } })
this gist mocks the original way vs this gist that uses 2 queries
Harishankar Ayandev
@harishankards
Apr 20 2018 11:01
Hey everyone! I'm trying mongoose in my project
Where I'm having one to many relationship between two. Student has many Projects

so my schema goes like this:
Student:
projects: [{ type: Schema.Types.ObjectId, ref: 'projects' }]

Project:
author : { type: Schema.Types.ObjectId, ref: 'Student' }

When I'm creating a project, I'm passing down the author id also. Still, it's not updating in Student's schema
How do I achieve this
?
Kev
@lineus
Apr 20 2018 11:13
@harishankards if you want the reference to the project stored in the student, you'll have to make a second query to the db and explicitly add the reference to the student.projects array.
feel free to share a gist of your current code that creates/saves the project if you want help with a specific aspect of doing so.
Harishankar Ayandev
@harishankards
Apr 20 2018 11:25
oh
@lineus I thought by referencing it, it will automatically adds to it
What's the advantage of reference then?
Kev
@lineus
Apr 20 2018 11:29
You only need to create the reference on one side. Creating it on both sides is extra work with no benefit that I can see.
@harishankards I'm curious what led you to choose the normalized route over embedding. If a project only has one author, what benefit do you get from having a separate collection of projects?
Harishankar Ayandev
@harishankards
Apr 20 2018 11:31
exports.createProject = (req, res) => {
  const title = req.body.title,
        abstract = req.body.abstract,
        description = req.body.description,
        author = req.body.author;

  if (title === '' || abstract === '' || description === '' || author === ''){
    res.status(403).send('Mandatory field missing')
  }
  else {
    Student.findOne({email:author}, (studentErr, student) => {
      if (studentErr) {
        console.log('error in finding the student', studentErr)
        res.status(403).send(studentErr)
      }
      else {
        console.log('found the student', student._id)
        const project = new Project ({
          title: title,
          abstract: abstract,
          description: description,
          author: student._id
        })
        project.save( (err, saved) => {
          if(err) {
            console.log('err in saving the project', err)
            res.status(403).send(err)
          }
          else {
            console.log('project saved', saved)
            res.status(200).send('project_creation_success')
          }
        }) 
      }
    })
  }
}
this is my code @lineus
I'm new to mongoose
Only one side is enough?
There are some cases will be there when I need to show the project even without the user
So, I thought it's better to go with separate collections
It's like a social network.
Makes sense?
Kev
@lineus
Apr 20 2018 11:33
yeah, that makes sense.
I have to take my kids to school. back in 15
Harishankar Ayandev
@harishankards
Apr 20 2018 11:34
cool @lineus
Kev
@lineus
Apr 20 2018 11:56
so, in the context of the code sample above, once you create the project for the student you can push the project._id onto the student's project array, save the student, and save the project.
exports.createProject = (req, res) => {
  const title = req.body.title,
        abstract = req.body.abstract,
        description = req.body.description,
        author = req.body.author;

  if (title === '' || abstract === '' || description === '' || author === ''){
    res.status(403).send('Mandatory field missing')
  }
  else {
    Student.findOne({email:author}, (studentErr, student) => {
      if (studentErr) {
        console.log('error in finding the student', studentErr)
        res.status(403).send(studentErr)
      }
      else {
        console.log('found the student', student._id)
        const project = new Project ({
          title: title,
          abstract: abstract,
          description: description,
          author: student._id
        })
       student.projects.push(project._id)
       student.save((err, updated) => {
          if (err) { return console.log(err) }
          project.save( (err, saved) => {
            if(err) {
              console.log('err in saving the project', err)
              res.status(403).send(err)
            }
            else {
              console.log('project saved', saved)
              res.status(200).send('project_creation_success')
            }
          })
        }) 
      }
    })
  }
}
Harishankar Ayandev
@harishankards
Apr 20 2018 11:57
Yes
That's what I'm gonna do
just now I came to know it never updates automatically
Also I added, why do we need relations then? We could just define [] for instead Schema.Objecttype and all right @lineus ?
Kev
@lineus
Apr 20 2018 12:05
references allow us to remove duplication of data, potentially increase read performance vs embedding, and they allow us to create many-many relationships. If you want to have the projects in a separate collection that's perfectly acceptable, you just don't need a one to one reference in both the student and the project.
either store the list of project references in the student, or store the single reference back to the student in the project, but having both isn't necessary.
Harishankar Ayandev
@harishankards
Apr 20 2018 12:31
super
Understood
Thanks for the great explanation @lineus
Kev
@lineus
Apr 20 2018 12:33
happy to help! glad to have you here @harishankards :)
Harishankar Ayandev
@harishankards
Apr 20 2018 12:33
There will be scenarios where I'll be needing author id of projects right. If I just refer in students, I need to get the project id, search through students and their associated projects right?
Ah! Thanks for the nice words :)
I have that scenario right, still it is not needed @lineus ?
Kev
@lineus
Apr 20 2018 12:44
@harishankards Yeah, you can query based on the student.projects array having an element that matches a specific project._id.
Harishankar Ayandev
@harishankards
Apr 20 2018 12:45
that will be more costly right?
Instead, I can have a look at the project owner ID right?
Kev
@lineus
Apr 20 2018 12:45
yeah, that works too ;)
Harishankar Ayandev
@harishankards
Apr 20 2018 12:46
cool man ;)
Thanks for the clarification
Bruno Barros
@bybrunobarros
Apr 20 2018 17:19

Hey everyone! It's quite difficult to explain in few words :) I'm trying to identify the kind of instance I'm working on. Let me explain it, here is a model

const schema = new Schema({
  children: [childSchema]
})

mongoose.model('Parent', schema)

I can identify a Parent instance with parent.constructor.modelName, but I didn't really find something about a child. There is a child.constructor.path attribute, but I wonder if there is a better way. Any Idea?

Nate Mallison
@NJM8
Apr 20 2018 17:28
@bybrunobarros Are you storing references to the child schema? list a list of todo's that belong to a user schema?
Bruno Barros
@bybrunobarros
Apr 20 2018 17:33
@NJM8 I'm not sure to understand the question, sorry 😅. A use case could be a company with several addresses. I want to pull an address out and work on it. When this address is passed as a function argument I'd like to recognise it as an address. Is that clear?
Nate Mallison
@NJM8
Apr 20 2018 17:33
I think if that is the case you should store a reference so you know where it came from, although I admit I don't know how to pull that ref so you know what it is, but this allows the Schema to know what collection to look in:
const userSchema = new mongoose.Schema({
  username: {
  type: String,
  required: true,
  unique: true
  }, 
  password: {
    type: String,
    required: true
  },
  isAdmin: {
    type: Boolean,
    default: false
  },
  items: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Item'
  }]
}, 
  {timestamps: true}
);
I think something like this might work where the items, is a stored _id and ref to another collection, although it sounds like you aren't referencing another collection, but just want to know what type of data you have?
Bruno Barros
@bybrunobarros
Apr 20 2018 17:37
Well I think you understand well what I mean. I don't use a ref in that case.
It's a subdocument not a reference
Nate Mallison
@NJM8
Apr 20 2018 17:39
got it
does it have it's own schema?
Bruno Barros
@bybrunobarros
Apr 20 2018 17:39
yes, it does
Kev
@lineus
Apr 20 2018 17:42
@bybrunobarros not sure if this is quite enough, but each subdocument will be an instance of an embedded doc
Nate Mallison
@NJM8
Apr 20 2018 17:44
I assume also the only reason you need to verify the childSchema type is because you are putting multiple childSchema's in one property? It would be easier maybe just to have a different location for each property.
consider these:
personSchema = {
  name: name,
  details: [[addressSchema], [phoneNumberSchema]]
}

personSchema = {
  name: name,
  address: [addressSchema],
  phoneNumber: [phoneNumberSchema]}
}
in the second case you don't have to validate what type of data you pulled from the details array to know how to handle it, just make it it's own thing.
Kev
@lineus
Apr 20 2018 17:52
@bybrunobarros gist for fun
Bruno Barros
@bybrunobarros
Apr 20 2018 17:53

Actually, the model is more like this

const schema = new Schema({
  bigThings: [bigSchema],
  smallThings: [smallSchema]
})

mongoose.model('Parent', schema)

I want to run a business rule against on of these without caring of their type on function call

const flag = isValid(parent.bigThings[0])

function isValid(thing) {
   if (/*thing is big*/) return bigBusinessRule()
   if (/*thing is small*/) return smallBusinessRule()
}

At this point I'm totally out of the model, but in the business layer.

So yes I could use a if earlier, but I'd like isValid() more generic, more like a facade
Bruno Barros
@bybrunobarros
Apr 20 2018 18:03
@lineus the gist is just checking kid is Embedded, am I right? if kids are divided in two collections of boys and girls, i'd like to know if it's a boy or a girl.
You can tell me I'm all wrong and it's useless, as well :)
Kev
@lineus
Apr 20 2018 18:04
no, not at all :)
I just didn't have that detail yet :)
you can add a virtual property to the children schema that returns a string that identifies it's type like this gist
easier than digging around in mongoose guts anyway
Bruno Barros
@bybrunobarros
Apr 20 2018 18:07
oh I was writing something totally in the other way 😁
So you think a virtual property is cleaner than child.constructor.path? And as far as I understand, it seems there is no proper way to do it, right?
Kev
@lineus
Apr 20 2018 18:12
If child.constructor.path works, I think that's fine :) I hadn't used it before, so I was going with a way that I knew would work :) hehe
Bruno Barros
@bybrunobarros
Apr 20 2018 18:13
The only thing I don't like it gives a path, not a model name
But ok, I see now. Thanks for your help @NJM8 @lineus
Nate Mallison
@NJM8
Apr 20 2018 18:22
@bybrunobarros Also could you just specify a pre-set piece of data on the bigThings and smallThings schema that just says, I'm a big thing or i'm a small thing?
Nathaniel Suchy
@nsuchy
Apr 20 2018 20:16
Just discovered indexes
didn't know I could query this fast
xD