1

I am working with mongoose schema and trying to get a parent obj in child from the child itself (I know it is not allowed in Javascript, but there are workarounds). This was my first implementation

const customer = mongoose.Schema({
    name: String,
    products_sold: [
        {
            name: String,
            price: Number,
            qty: Number,
        },
        {
            name: String,
            price: Number,
            qty: Number,
        },
    ],
    messages: [
        {
            timestamp: { 
                type : Date, 
                default: Date.now 
            },
            _my_key_: {
                type: String,
                default: () => {
                    // here i need to get products_sold.name in array like [products_sold[0].name, products_sold[1].name]
                    // this.products_sold does not work
                },
            },
        }
    ]
})

I looked up some resources like this one. So i also tried

const customer = mongoose.Schema({
    name: String,
    products_sold: [
        {
            name: String,
            price: Number,
            qty: Number,
        },
        {
            name: String,
            price: Number,
            qty: Number,
        },
    ],
    messages: [
        {
            timestamp: { 
                type : Date, 
                default: Date.now 
            },
            _my_key_: {
                type: String,
                default: () => {
                    // here this.parent.products_sold does not work also
                },
            },
        }
    ],
    init: function(){
        this.messages._my_key_.parent = this;
        delete this.init;
        return this;
    }  
}.init()
)

For Reference: Mongoose Default Functions and This

This question does not answer mine.

EDIT # 1

I tried this with both arrow and regular function.

EDIT # 2

As per comment feedback from @Molda. After the above code, This is how i make the instance and save a record.

const Customer = mongoose.model('Customer', customer);

const customer = {
    name: "John Doe",
    products_sold: [
        {
            name: "product_name",
            price: 1245,
            qty: 2,
        }
    ],
    messages: [
        {
            // message timestamp will generate from default and _my_key_ too will generate from default
        }
    ]
}

const callingFunc = async () => {
    const cust = await Customer(customer);
    await cust.save();
    return cust;
};
Huzaifa
  • 345
  • 4
  • 15
  • Well you are using `fat arrow function` which does not have a scope so there's no `this`. Try `default: function(){ console.log(this) }` <- this should be the document. https://stackoverflow.com/a/38589422/3284355 – Molda Mar 06 '21 at 20:50
  • @Molda, My Bad, I forgot to mention, I tried that too. – Huzaifa Mar 06 '21 at 20:51
  • Can you add the code you tried to create a model instance? Did you do something like this `var model = new Customer({ some props })`? I tried this `const schema = new Schema({ name: String, date: { type: Date, default: function(){ console.log('THIS', this); return Date.now(); }}});` and it works as expected like this `const new_customer = new Customer({ name: 'Hello world' });` `console.log('THIS', this);` in default function returns an object with name property. Please add the code you tried and show the value of `this` within the default function. – Molda Mar 06 '21 at 21:03
  • Yeah sure i will add that. Also referring to your example ```const schema = new Schema({ name: String, date: { type: Date, default: function(){ console.log('THIS', this); return Date.now(); }}});```. This works on my side tho but my use case is different (accessing parent from the child). In the case of your example it would be ```const schema = new Schema({ name: String, somekey: [ date: { type: Date, default: function(){ console.log('THIS', this.name); return Date.now(); }}] });``` – Huzaifa Mar 06 '21 at 21:11
  • I just tried with your schema and it seems when you create model instance you have to pass in `..., messages: [{}]` otherwise it doesn't work. But it kind of makes sense since messages is an array and it doesn't know how many messages you want to create. – Molda Mar 06 '21 at 21:16
  • I am a bit confused, didn't got that. How should i pass `..., messages: [{}]` from model instance. – Huzaifa Mar 06 '21 at 21:27
  • Just like you do in your second EDIT code, the only thing wrong is `await Customer(...)` it should be `new Customer(...)` you dont need to use `await` since Customer does not return a promise. – Molda Mar 06 '21 at 21:40
  • I just tried that but i couldn't still access the parent obj from the child in the default function. Based on one of your previous recommendation, I tried console.log(escape(this)) in the default function and i get `timestamp` and `_my_key_ ` but i couldn't get the `products_sold`. I also tried `console.log(this)` in `init function ` which gives `[object Object]` but gives undefined when i try `this.name` – Huzaifa Mar 07 '21 at 11:55
  • 1
    So i just found out that mongoose treats subdocuments in array as documents so `this` refers to the object in that array not the parent. It seems you were on the right path with the `this.parent` the only problem is that it is a function so while this `this.parent.products_sold` doesn't work `this.parent().products_sold` works just fine. – Molda Mar 07 '21 at 16:29
  • @Molda It worked.... Thanks a lot. You should post this as an answer. – Huzaifa Mar 07 '21 at 17:30

0 Answers0