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 is sort order maintained when using the object notation? #4941

Closed
troxler opened this issue Jan 30, 2017 · 11 comments
Closed

How is sort order maintained when using the object notation? #4941

troxler opened this issue Jan 30, 2017 · 11 comments

Comments

@troxler
Copy link

troxler commented Jan 30, 2017

ECMAScript defines an object as follows:

It is an unordered collection of properties each of which contains a primitive value, object, or function.

So when using the sort method with the object notation (e.g. query.sort({ field: 'asc', test: -1 });), how can the order of the keys actually be maintained? Currently, V8 does maintain the order, but can we rely on that to never change?

The official Node MongoDB driver actually suggests to use different notations for whether there is one or several sort properties:

Sorting can be acieved with option parameter sort which takes an array
of sort preferences

{   "sort": [['field1','asc'], ['field2','desc']] }

With single ascending field the array can be replaced with the name of the field.

{   "sort": "name" }
@vkarpov15
Copy link
Collaborator

Yep, that's an unfortunate dilemma for both mongoose and the mongodb driver. ECMAScript says that keys are not ordered, but they are actually ordered in V8 (except for numeric keys, which is a nasty edge case), and likely will continue to be ordered in V8 for the foreseeable future. You can use the [['field1', 'asc']] syntax or the mongoose-specific 'field1 -field2' syntax or the ES2015 Map class (which guarantees insertion order for keys) if you're concerned with key order.

vkarpov15 added a commit to mongoosejs/mquery that referenced this issue Feb 1, 2017
@vkarpov15 vkarpov15 added this to the 4.8.2 milestone Feb 1, 2017
@vkarpov15 vkarpov15 reopened this Feb 1, 2017
@troxler
Copy link
Author

troxler commented Feb 1, 2017

Thanks for clarifying and adding support for Maps.

@aguyinmontreal
Copy link

aguyinmontreal commented Dec 4, 2017

@vkarpov15

I tried to use this syntax [['field1', 'asc'],['field2', 'desc']] inside .aggregate

but I got this error:

"name":"MongoError","message":"the $sort key specification must be an object"

@vkarpov15
Copy link
Collaborator

@aguyinmontreal what version of mongoose and mongodb?

@aguyinmontreal
Copy link

@vkarpov15 Mongoose 4.7.4 MongoDB 3.4.1

@tonybranfort
Copy link

tonybranfort commented Dec 15, 2017

Sort using Map fails for me (mongoose v 4.10.5, mongodb 3.4.10). Here's what I've tried:
SomeModel.find({}).sort(new Map([['eventId','asc'],['level','desc']]))
SomeModel.find({}).sort(new Map([['eventId',1],['level',1]]))
SomeModel.find({},{},{sort: new Map([['eventId',1],['level',1]])})
SomeModel.find({}).sort(new Map().set('field', 1).set('test', -1))

And the error I get:

MongoError: bad sort specification
      at Function.MongoError.create (node_modules\mongoose\node_modules\mongodb-core\lib\error.js:31:11)
      at queryCallback (node_modules\mongoose\node_modules\mongodb-core\lib\cursor.js:212:36)
      at node_modules\mongoose\node_modules\mongodb-core\lib\connection\pool.js:469:18
      at _combinedTickCallback (internal/process/next_tick.js:131:7)
      at process._tickDomainCallback (internal/process/next_tick.js:218:9)

@vkarpov15
Copy link
Collaborator

@tonybranfort you don't need to use Map, just do [['eventId', 1]]

@tonybranfort
Copy link

Thanks vkarpov15. I don't actually create the Map for the sort. It already exists before the sort - thought I could sort without converting it out of a Map. No problem to convert it before the sort. And thanks for all your work on Mongoose.

@NikitaVlaznev
Copy link

NikitaVlaznev commented Oct 7, 2018

Still getting the "the $sort key specification must be an object" error when running:

aggregate([{"$sort":[["name",-1]]}, {"$limit":10}]);

Mongoose 5.3.1.
Mongo Server: 3.4.2

@vkarpov15
Copy link
Collaborator

@NikitaVlaznev I'm not certain MongoDB aggregation supports that syntax, but I'll double check

@vkarpov15 vkarpov15 reopened this Oct 11, 2018
@vkarpov15 vkarpov15 modified the milestones: 4.8.2, 5.3.5 Oct 11, 2018
@vkarpov15 vkarpov15 added the needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue label Oct 11, 2018
@vkarpov15 vkarpov15 modified the milestones: 5.3.5, 5.3.6 Oct 16, 2018
@vkarpov15 vkarpov15 modified the milestones: 5.3.7, 5.3.8 Oct 26, 2018
@vkarpov15
Copy link
Collaborator

Yeah unfortunately the MongoDB server does not support the array-based syntax. However, you don't actually need this syntax since the ES6 spec specifies the order of keys in an object, so any spec-compliant JS runtime like node is going to give you the right key order every time.

@vkarpov15 vkarpov15 removed this from the 5.3.8 milestone Oct 30, 2018
@vkarpov15 vkarpov15 added won't fix and removed needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue labels Oct 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants