Sometimes I like to go back to the start. When I create a database index, I know what it does, it's just a reverse lookup. But coding it, you see how unique indexes can be different from non-unique indexes.
Postgres has "index de-duplication", but it happens lazily and wasn't added until version 13. I see at least two types of index but they don't need to be done lazily:
PrimaryIndex<uint64_t, 4> itemIdPrimaryIndex = {
{ 2000, 2001, 2002, 2003 }, // item id
{ 0, 32, 72, 120 }, // storage offset
};
SecondaryIndex<uint64_t, 3, 4> itemTeamIdSecondaryIndex = {
{ 100, 101 }, // team id
{ 0, 2, 4 }, // index into first matching key (with end of range index)
{ 32, 0, 120, 72 }, // storage offset, secondarily sorted by updated_date};
So now I should be able to get all items by team, sorted by updated_date, all in one index. Again nothing enlightening, rather obvious, but it's fun to go bare bones to really think about something. The structs of array vs array of structs is for SIMD and cache optimization.
Postgres also has a "covering index" where you can stuff data in the index node. Maybe good for small things but it will bloat your index, and B-Tree pages are only 4K or so.
Conditional indexes are interesting, because if you're only interested in one team for example, you can just index on that and the it will not index teams.