Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to keep the fields order in DB when creating a new doc? #6944

Closed
flight9 opened this issue Aug 30, 2018 · 3 comments
Closed

How to keep the fields order in DB when creating a new doc? #6944

flight9 opened this issue Aug 30, 2018 · 3 comments
Milestone

Comments

@flight9
Copy link

flight9 commented Aug 30, 2018

Do you want to request a feature or report a bug?
Maybe a bug. Not sure

What is the current behavior?
When u save a new doc, it's fields order can't be kept as defined in schema or its orignal order.

If the current behavior is a bug, please provide the steps to reproduce.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
mongoose.connect('mongodb://YOUR_CONNECTION_STRING');

const articleSchema = new Schema({
  'ug_guid': {
    'type': 'String'
  },
  'assetTypeId': {
    'type': Schema.Types.ObjectId,
    'ref': 'assetTypes'
  },
  'mesa_key': {
    'type': 'String'
  },
  'site_specific_name': {
    'type': 'String'
  },
  'serial_number': {
    'type': 'String'
  },
  'mesaTrees': {
    'what': [
      {
        'ns1': {
          'type': 'String'
        },
        'ns2': {
          'type': 'String'
        },
        'what1': {
          'type': 'String',
          'required': true
        },
        'what2': {
          'type': 'String'
        },
        'what3': {
          'type': 'String'
        },
        'what4': {
          'type': 'String'
        },
        'what5': {
          'type': 'String'
        },
        'what6': {
          'type': 'String'
        },
        'what7': {
          'type': 'String'
        },
        'what8': {
          'type': 'String'
        }
      }
    ],
    'ent': [
      {
        'ent1': {
          'type': 'String',
          'required': true
        },
        'ent2': {
          'type': 'String'
        },
        'ent3': {
          'type': 'String'
        }
      }
    ],
    'at': {
      'type': 'String'
    }
  }
});
const Article = mongoose.model('Article', articleSchema);

let data = { 
  ug_guid: '6db93bc6-f0eb-4c31-b4db-4b90a185f927',
  assetTypeId:'5a436c14fb18bba37f8384e3',
  mesa_key: 'mesa_key2_1',
  site_specific_name: 'B Test Site',
  serial_number: '93425726762957156',
  mesaTrees:{ 
    what:
      [ { ns1: 'namespace1',
          ns2: 'namespace2',
          what1: 'what1',
          what2: 'what2',
          what3: 'what3',
          what4: 'what4',
          what5: 'what5',
          what6: 'what6',
          what7: 'what7',
          what8: 'what8',
          _id: '5a436c14fb18bba37f8384e3' } ],
    ent:
      [ { ent1: 'ent1',
          ent2: 'ent2',
          ent3: 'ent3',
          _id: '5a436c14fb18bba37f8384e3' 
        },
        { ent1: 'ent4',
          ent2: 'ent5',
          ent3: 'ent6',
          _id: '5a436c14fb18bba37f8384e3'
        }
      ],
    at: 'at1' 
  } 
};
var art = new Article(data);
art.save(function (err) {
  if (err) {
    console.error('Error:', err);
  }
});

But I got the order in MongoDB like: (NOTE: mesaTrees is promoted to front.)

{
    "_id" : ObjectId("5b878bc0e81523a511b0c42b"),
    "mesaTrees" : {
        "what" : [ 
            {
                "_id" : ObjectId("5a436c14fb18bba37f8384e3"),
                "ns1" : "namespace1",
                "ns2" : "namespace2",
                "what1" : "what1",
                "what2" : "what2",
                "what3" : "what3",
                "what4" : "what4",
                "what5" : "what5",
                "what6" : "what6",
                "what7" : "what7",
                "what8" : "what8"
            }
        ],
        "ent" : [ 
            {
                "_id" : ObjectId("5a436c14fb18bba37f8384e3"),
                "ent1" : "ent1",
                "ent2" : "ent2",
                "ent3" : "ent3"
            }, 
            {
                "_id" : ObjectId("5a436c14fb18bba37f8384e3"),
                "ent1" : "ent4",
                "ent2" : "ent5",
                "ent3" : "ent6"
            }
        ],
        "at" : "at1"
    },
    "ug_guid" : "6db93bc6-f0eb-4c31-b4db-4b90a185f927",
    "assetTypeId" : ObjectId("5a436c14fb18bba37f8384e3"),
    "mesa_key" : "mesa_key2_1",
    "site_specific_name" : "B Test Site",
    "serial_number" : "93425726762957156",
    "__v" : 0
}

What is the expected behavior?
Keep the fields order in DB as defined in schema or its orignal order.

Version
node.js: 8.9.3
mongoose: 5.2.10
MongoDB: 3.6.1

@lineus
Copy link
Collaborator

lineus commented Aug 30, 2018

@flight9 if you add a type property to your mesaTrees schema path object like all of your other paths, the order is restored.

Here is an example using your schema with the suggested change:

6944.js

#!/usr/bin/env node
'use strict';

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
const conn = mongoose.connection;
const Schema = mongoose.Schema;

const articleSchema = new Schema({
  'ug_guid': {
    'type': 'String'
  },
  'assetTypeId': {
    'type': Schema.Types.ObjectId,
    'ref': 'assetTypes'
  },
  'mesa_key': {
    'type': 'String'
  },
  'site_specific_name': {
    'type': 'String'
  },
  'serial_number': {
    'type': 'String'
  },
  'mesaTrees': {
    type: {
      'what': [
        {
          'ns1': {
            'type': 'String'
          },
          'ns2': {
            'type': 'String'
          },
          'what1': {
            'type': 'String',
            'required': true
          },
          'what2': {
            'type': 'String'
          },
          'what3': {
            'type': 'String'
          },
          'what4': {
            'type': 'String'
          },
          'what5': {
            'type': 'String'
          },
          'what6': {
            'type': 'String'
          },
          'what7': {
            'type': 'String'
          },
          'what8': {
            'type': 'String'
          }
        }
      ],
      'ent': [
        {
          'ent1': {
            'type': 'String',
            'required': true
          },
          'ent2': {
            'type': 'String'
          },
          'ent3': {
            'type': 'String'
          }
        }
      ],
      'at': {
        'type': 'String'
      }
    }
  }
});

const Article = mongoose.model('Article', articleSchema);

let data = {
  ug_guid: '6db93bc6-f0eb-4c31-b4db-4b90a185f927',
  assetTypeId: '5a436c14fb18bba37f8384e3',
  mesa_key: 'mesa_key2_1',
  site_specific_name: 'B Test Site',
  serial_number: '93425726762957156',
  mesaTrees: {
    what:
      [{
        ns1: 'namespace1',
        ns2: 'namespace2',
        what1: 'what1',
        what2: 'what2',
        what3: 'what3',
        what4: 'what4',
        what5: 'what5',
        what6: 'what6',
        what7: 'what7',
        what8: 'what8',
        _id: '5a436c14fb18bba37f8384e3'
      }],
    ent:
      [{
        ent1: 'ent1',
        ent2: 'ent2',
        ent3: 'ent3',
        _id: '5a436c14fb18bba37f8384e3'
      },
      {
        ent1: 'ent4',
        ent2: 'ent5',
        ent3: 'ent6',
        _id: '5a436c14fb18bba37f8384e3'
      }
      ],
    at: 'at1'
  }
};

var art = new Article(data);

async function run() {
  await conn.dropDatabase();
  await art.save();
  let doc = await Article.collection.findOne({});
  console.log(doc);
  return conn.close();
}

run();

Output:

issues: ./6944.js
{ _id: 5b87bd3a80feb70f7ae23e5a,
  ug_guid: '6db93bc6-f0eb-4c31-b4db-4b90a185f927',
  assetTypeId: 5a436c14fb18bba37f8384e3,
  mesa_key: 'mesa_key2_1',
  site_specific_name: 'B Test Site',
  serial_number: '93425726762957156',
  mesaTrees: { what: [ [Object] ], ent: [ [Object], [Object] ], at: 'at1' },
  __v: 0 }
issues:

I'm not sure if this is a bug, I'll leave this open and we'll investigate. Thanks for reporting this!

@lineus lineus added the bug? label Aug 30, 2018
@flight9
Copy link
Author

flight9 commented Aug 31, 2018

@lineus thanks

@vkarpov15 vkarpov15 added this to the 5.2.15 milestone Sep 3, 2018
@vkarpov15 vkarpov15 modified the milestones: 5.2.16, 5.2.17 Sep 10, 2018
@vkarpov15 vkarpov15 modified the milestones: 5.2.17, 5.2.18 Sep 21, 2018
vkarpov15 added a commit that referenced this issue Sep 26, 2018
@vkarpov15
Copy link
Collaborator

@lineus be careful, your solution converts mesaTrees to a Mixed type. As a workaround, do this instead:

const articleSchema = new Schema({
  'ug_guid': {
    'type': 'String'
  },
  'assetTypeId': {
    'type': Schema.Types.ObjectId,
    'ref': 'assetTypes'
  },
  'mesa_key': {
    'type': 'String'
  },
  'site_specific_name': {
    'type': 'String'
  },
  'serial_number': {
    'type': 'String'
  },
  'mesaTrees': new Schema({
      'what': [
        {
          'ns1': {
            'type': 'String'
          }
        }
      ]
  });
});

That should work better.

The issue here is that Mongoose's steps for creating a new document via new Article() are:

  1. $__buildDoc()
  2. $__applyDefaults()
  3. Initial set

$__buildDoc() sets all nested paths, like mesaTrees, to an empty object {} by default. Mongoose then modifies the default empty object in place during initial set, so nested paths always come first in key order. This key order switch is very confusing and something we're going to have to improve on in general, but the above fix includes a reasonable solution that should cover the vast majority of cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants