30

I have a model like this:

var userSchema = new mongoose.Schema({
  _id: { type: Schema.ObjectId },
  email: { type: String, unique: true },
  ipAddress: { type: String },
  referals: [{
    type: mongoose.Schema.Types.ObjectId, ref: 'User'
  }],
  redeem_token: {type: String, unique: true}
});

var User = mongoose.model('User', userSchema);

Can this work? The user, needs to have a reference to other users. It's to track signup referrals. I want to then use .Populate and expand the users in the referals[]

ZygD
  • 22,092
  • 39
  • 79
  • 102
  • 1
    Sure, that should work. Did you try it? – JohnnyHK Jul 26 '14 at 02:03
  • 3
    Yes it worked exactly as it should! I was just thinking about it in class and had nowhere to test it; truthfully, a question here was probably unnecessary, I just didn't want to lose the thought without an answer! Thank you for the response. –  Sep 09 '14 at 10:04

4 Answers4

34

I'm using Mongoose. This works for me, I'm simply using this as a reference to the model. I have a Comment model. Comments can have a reply that is also Comment.

var Comment = new mongoose.Schema({
  id: { type: ObjectId, required: true },
  comment:    { type: String },
  replies:    [ this ],
});    
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
rat
  • 1,277
  • 16
  • 24
  • 4
    Ok. This works, but how is it possible? I would thing that `this` would be referencing whatever is the context when the `Schema` constructor is being called. I'm confused. – kub1x Jun 24 '18 at 17:46
  • can you tell what would be the query to get all replies for a comment? – Akshay Singh Aug 09 '19 at 13:54
  • @kub1x Probably mongoose use a .bind(thisSchema) somewhere :https://www.javascripttutorial.net/javascript-bind/ – Albert James Teddy Jan 15 '22 at 18:05
  • @AlbertJamesTeddy That would only work for `this` within the code of the bound function. We're outside of any of that. – kub1x Jan 16 '22 at 19:56
  • 1
    @kub1x You're probably right, I have been looking at the source code, I can't find anything related to using `this` to denote self reference. I wonder if `this` is just treated as a Mixed type. – Albert James Teddy Jan 16 '22 at 23:14
4

I know this question is old. But I stumbled upon this as I was looking for a solution to a similar problem. So, this is for future knowledge seekers!

Ankur's answer will help if you want the referals created inside the user document. Ex:

{
  _id: 'XXX',
  ...
  referals: [{_id:'yyy',email: ''}]
}

I think Using Mongoose Virtuals will help scale the application better. With virtuals, you wouldn't have to create duplicate records.

So if you decide to use Mongoose Virtuals, your schema would look like this

var userSchema = new mongoose.Schema({
  _id: { type: Schema.ObjectId },
  email: { type: String, unique: true },
  ipAddress: { type: String },
  referedBy: {
    type: mongoose.Schema.Types.ObjectId, ref: 'User'
  },
  redeem_token: {type: String, unique: true}
});

userSchema.virtuals('refereals',{
   ref: 'User',
   localField: '_id',
   foreignField: 'referedBy',

   justOne: false,
},{ toJSON: { virtuals: true } }); /* toJSON option is set because virtual fields are not included in toJSON output by default. So, if you don't set this option, and call User.find().populate('refereals'), you won't get anything in refereals */

var User = mongoose.model('User', userSchema);

Hope this helps. If I am wrong, please correct me as I am new to this.

Jijo
  • 151
  • 7
0

For those stuck on trying to make infinite children:

https://stackoverflow.com/a/72603609/4594452

The answer of that is --

mongoose schema:

const itemSchema = new mongoose.Schema({
  name: String,
  items: {
    type: [this],
    default: undefined
  }
}, { _id: false })

const mainSchema = new mongoose.Schema({
  name: String,
  items: {
    type: [itemSchema],
    default: undefined
  }
})

output example:

[
  {
    _id: '62a72d6915ad7f79d738e465',
    name: 'item1',
    items: [
      {
        name: 'item1-item1',
        items: [
          {
            name: 'item1-item1-item1'
          },
          {
            name: 'item1-item1-item2'
          },
          {
            name: 'item1-item1-item3'
          },
        ]
      },
      {
        name: 'item1-item2'
      }
    ]
  },
  {
    _id: '62a72d6915ad7f79d738e467',
    name: 'item2'
  },
  {
    _id: '62a72d6915ad7f79d738e467',
    name: 'item3',
    items: [
      {
        name: 'item3-item1'
      }
    ]
  }
]
Miko Chu
  • 1,087
  • 14
  • 22
0

you can use

const itemsObj = { _id: {type: String}, items: {type: [this]} }

const itemSchema = new mongoose.Schema({...itemsObj, items: [...itemsObj]})

so that you can reference self with _id included.

If you don't need assign "_id" for children items, then {type: [this]} is enough

Jay
  • 11
  • 4