I have a mongoose schema:
models/profile.js
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var profileSchema = new mongoose.Schema({
username: String,
complete: { type: Boolean, default: false },
email: { type: String, default: "" },
city: { type: String, default: "" }
}, { discriminatorKey: 'accountType' });
profileSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('Profile', profileSchema);
That has two discriminators associated with it:
models/finder.js
var Profile = require('./profile');
var Finder = Profile.discriminator('finder', new mongoose.Schema({
position: { type: String, default: "" },
skills: Array
}));
module.exports = mongoose.model("Finder");
models/helper.js
var Profile = require('./profile');
var Helper = Profile.discriminator('helper', new mongoose.Schema({
jobTitle: { type: String, default: "" },
lastPosition: { type: String, default: "" }
}));
module.exports = mongoose.model("Helper");
I am using this within an express framework, and on one page - shown below - I want to iterate over the key/value pairs in Profile
to build a table.
I would like to retain the order designated in the Schema, so that the table ordering is consistent between pages.
Is it possible to define a sort order on Schema creation?
Here's my profile.ejs
file where I make the table:
<table class="table profile-display">
<tbody>
<% for(var key in profile.toObject({versionKey: false})) { %>
<% if (key != '_id') { %>
<% if (profile[key].length === 0){ %>
<tr class="incomplete-warning table-rows">
<% } else { %>
<tr class="table-rows">
<% } %>
<td class="key-text"><%=key.toUpperCase()%>:</td>
<td><%=profile[key]%></td>
</tr>
<% } %>
<% } %>
</tbody>
</table>
Please let me know if I can provide more information
You can use retainKeyOrder
By default, mongoose reverses key order in documents as a performance optimization. For example, new Model({ first: 1, second: 2 });
would actually be stored in MongoDB as { second: 2, first: 1 }
. This behavior is considered deprecated because it has numerous unintended side effects, including making it difficult to manipulate documents whose _id field is an object.
Mongoose >= 4.6.4 has a retainKeyOrder
option for schemas that ensures that mongoose will always keep the correct order for your object keys.
var testSchema = new Schema({ first: Number, second: Number }, { retainKeyOrder: true });
var Test = mongoose.model('Test', testSchema);
Test.create({ first: 1, second: 2 }); // Will be stored in mongodb as `{ first: 1, second: 2 }`
References:
https://github.com/Automattic/mongoose/issues/1514 https://mongoosejs.com/docs/4.x/docs/guide.html#retainKeyOrder
Every browser handles object sorts differently. I suggest returning a JSON object which maps your schema that has a sort value or such and iterates over your profile.ejs
template. Then you can just map the value from mongoose output key whichever you like.
{
1 : 'username',
2 : 'type',
3 : 'complete',
4 : 'email',
5 : 'city',
6 : 'position',
7 : 'skills'
}
or an array
[
'username',
'type',
'complete',
'email',
'city',
'position',
'skills'
]
Then from that, you can just map your schema from the value of the object or from the array. I like using an array in this case as its easier to iterate over by just using the index key. It depends on your usage and purpose.
Hope it help.
UPDATE: To minimizing in hardcoding the schema twice you can create an object which has sorts with the schema value.
Code Example.
// Construct your object
var objSchema = {
obj1 : {
schema : { type: String },
order : 2
},
obj2 : {
schema : { type: String },
order : 3
},
obj3 : {
schema : { type: String },
order : 1
}
}
// Function to construct your schema object and sort array
function mapSortSchema(objs) {
var result = {
schema : {},
order : []
}
for (var obj in objs) {
result.schema[obj] = objs[obj].schema;
result.order.push({
'key': obj,
'order': objs[obj].order
});
}
result.order.sort(function(a, b) {
return a.order - b.order;
});
return result;
}
Now you have schema for mongoose and order for template.
var mapSchema = mapSortSchema(objSchema);
// You can now use this with your mongoose schema
var forMongooseSchema = mapSchema.schema;
// result {obj1 : { type: String }, obj2 : { type: String }, obj3 : { type: String }}
// You can now use this to loop through your template
var forTemplateLoop = mapSchema.order;
// result [{key: "obj3", order: 1}, {key: "obj1", order: 2}, {key: "obj2", order: 3}]
Haven't tested this in mongoose but it will give you the basic idea, you can improve the function base on your need. Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With