Order alphabetically using Cypher

What is the best way to order nodes alphabetically in Cypher? I see that ORDER BY orders String values by character code, so that von Trapp would come after Xhaka, but before Özil:

CREATE (:Person {surname: 'von Trapp', givenName: 'Maria'});
CREATE (:Person {surname: 'von Trapp', givenName: 'Agathe'});
CREATE (:Person {surname: 'Özil', givenName: 'Mesut'});
CREATE (:Person {surname: 'Xhaka', givenName: 'Granit'});
MATCH (p:Person) RETURN p.surname, p.givenName ORDER BY p.surname, p.givenName;
p.surname p.givenName
Xhaka Granit
von Trapp Agathe
von Trapp Maria
Özil Mesut

I've found the apoc.coll.sortText function, which does sort as expected, but it operates on lists of String rather than nodes, so (given the same nodes as before), I can do:

MATCH (p:Person)
WITH apoc.coll.sortText(collect(p.surname)) AS surnames
UNWIND surnames AS surname
RETURN surname
surname
Özil
von Trapp
von Trapp
Xhaka

Unfortunately, this discards the rest of the node (and only sorts by one property, so the two von Trapps can't use givenName as a secondary sort order).

Is there a way to use apoc.coll.sortText to sort nodes? Or is there another way to sort alphabetically, perhaps without resorting to APOC?

The apoc.coll.sortNodes can be used to sort a collection of nodes:

MATCH (p:Person)
WITH apoc.coll.sortNodes(COLLECT(p), "surname") AS people
UNWIND people AS p
RETURN p.surname
-----------------------------------------------------------
╒═══════════╕
│"p.surname"│
╞═══════════╡
│"Özil"     │
├───────────┤
│"von Trapp"│
├───────────┤
│"von Trapp"│
├───────────┤
│"Xhaka"    │
└───────────┘

Looking at the APOC code, apoc.coll.sortNodes sorts by character code, the same as ORDER BY, but defaults to descending, which gives the illusion with my sample data set of doing the right thing. :frowning:

Adding another node demonstrates:

CREATE (:Person {surname: 'Rossi', givenName: 'Francis'});
MATCH (p:Person)
WITH apoc.coll.sortNodes(COLLECT(p), "surname") AS people
UNWIND people AS p
RETURN p.surname, p.givenName
p.surname p.givenName
Özil Mesut
von Trapp Maria
von Trapp Agathe
Xhaka Granit
Rossi Francis
Try this:

MATCH (p:Person)
where p.surname is not null
with collect({surname: p.surname,  givenname: p.givenName}) as  sur
unwind sur as sur1
with sur1 order by sur1.surname
return sur1.surname, sur1.givenname

This also seems to give character code ordering :frowning:

sur1.surname sur1.givenname
Rossi Francis
Xhaka Granit
von Trapp Maria
von Trapp Agathe
Özil Mesut