1

Recently, I got a quite wired question on Mongoose, It's about the using of array. There is different use experience but I cannot find out any discussion or issue on this, so I tried to explain here, and ask someone know what's happened.

In javascript, Object is added as reference to array

    let existed;
    let company = { _id: "87" };
    let post = { evaluations: [] };
    let cost = 5;
    let predictDays = 1;
    let content = "8";
    if(!existed)
    {
        existed = {};
        existed.company = company._id;
        post.evaluations.push(existed);
    }

    existed.cost = cost || 99999999;
    existed.predictDays = predictDays || 100;
    existed.content = content || "";
    console.log(existed);
    console.log(post.evaluations);
Output:
{company: "87", cost: 5, predictDays: 1, content: "8"}
[{company: "87", cost: 5, predictDays: 1, content: "8"}]

In nodejs + mongoose, I got the totally different experience.

post is Document from findById.

    let existed;
    if(!existed)
    {
        existed = {};
        existed.company = company._id;
        post.evaluations.push(existed);
        /* existed = post.evaluations.find((evaluation) => {
            return evaluation.company.toString() === company._id.toString();
        });*/ // Uncomments this would make existed get the working reference as javascript
    }
    existed.cost = cost || 99999999;
    existed.predictDays = predictDays || 100;
    existed.content = content || "";
    console.log(existed);
    console.log(post.evaluations);
Output:
{
  company: 5d655f7743e25137f8501c38,
  cost: 50,
  predictDays: 3,
  content: '123321'
}
[{"company":"5d6562bfef7d771e4815dd4f"}]

I cannot figure out why It's not working, but If I uncomment the code, that findagain in array, I could get the expected result as below:

{
  company: 5d655f7743e25137f8501c38,
  cost: 50,
  predictDays: 3,
  content: '123321'
}
[{"company":"5d6563391fc9b65250e83988","cost":50,"predictDays":3,"content":"123321"}]

Did mongoose change the push behavior secretly? Hope It's enough infomation to point out my issue, any information is greatly appreciated.

2
  • Difference between [{company: "87", cost: 5, predictDays: 1, content: "8"}] vs [{"company":"5d6563391fc9b65250e83988","cost":50,"predictDays":3,"content":"123321"}] Commented Aug 27, 2019 at 17:22
  • Make a minimal example in Javascript, so let someone use It conveniently is wrong in your experience? I cannot provide my whole backend implementation. Commented Aug 27, 2019 at 17:29

2 Answers 2

1

I found out the source code for current version (5.6.11), and It explain why the push is working out of expected.

  /**
   * Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
   *
   * @param {Object} [args...]
   * @api public
   * @method push
   * @memberOf MongooseArray
   */

  push() {
    if (this[arraySchemaSymbol] == null) {
      return _basePush.apply(this, arguments);
    }

    _checkManualPopulation(this, arguments);

    let values = [].map.call(arguments, this._mapCast, this);
    values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol], undefined,
      undefined, { skipDocumentArrayCast: true });
    const ret = [].push.apply(this, values);

    this._registerAtomic('$push', values);
    this._markModified();
    return ret;
  }

I can't understand It totally, but I tried to describe here with my conjecture.

  1. Mongoose need to convert javascript object into sub-document when push a object. (I thought It checked on save())

  2. MongooseArray.push() copy object's properties to a new object, so the original reference passed from the parameter is not actually added.

It's just weak explanation, Hope someone could help to explain It better.

Sign up to request clarification or add additional context in comments.

Comments

0

Yes mongoose array's are different they have their own implementation of push , pop etc on their prototype. You can find the documentation here

4 Comments

Thanks for infomation, I also see this before I post, but you know the documentation nearly write nothing on push, so I decided to ask here :(
I thought you just wanted to know if they change behavior of push secretly. :P
Yeah, but this documentation could not convince me that the issue is exactly caused by this, maybe source code could explain this, but I tried my best and got lost...
MongooseArray.prototype.push() This means each mongoose array have these methods implemented on its prototye. I think you should read about prototypes a little.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.