Reputation: 6568
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
Upvotes: 7
Views: 6948
Reputation: 436
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.
Upvotes: 0
Reputation: 7080
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
Upvotes: 2