@DaveOak This is a great question. We spoke briefly over Gitter so I’m glad we can discuss the options in the forums. It’s easier to give examples.
am I right in thinking that there are no server runtime equivalents for ListGroups and ListGroupUsers?
You can find both ListGroups and ListGroupUsers in the server runtime. Have a look for "nk.user_groups_list"
and "nk.group_users_list"
:
https://heroiclabs.com/docs/runtime-code-function-reference/#groups
I can put the tag in the name field, and the name in the description field (or metadata) but then I can only search on tag.
I would suggest you keep the name in the name field of the group structure and put the tag into the group metadata and then can assign a unique index to it inside a run_once
function. This requires that you drop under the hood of the main API but can carefully add the additional customizations you need.
NOTE: Never make changes to the database tables in the Nakama schema itself. This could cause all kinds of errors in the queries written for the API built into the game server. Indexes and separate tables if absolutely needed.
nk.run_once(function()
-- Add a unique constraint to group metadata tag fields.
local sql = [[
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS groups_metadata_tag_uniq_idx
ON groups (((metadata->>'tag')::TEXT)) WHERE (metadata->>'tag') NOT IN (NULL, '');
]]
nk.sql_exec(sql, {})
end)
You can then perform a query over that JSON field in the metadata to efficiently look up on the tag:
SELECT name, description, id, metadata, edge_count FROM groups WHERE (metadata->>'tag') ILIKE 'sometag%'
The use of "ILIKE"
(case-insensitive LIKE) and the "%"
wildcard is a postfix search on the index which is pretty fast if you want to show results which partially match the “sometag” string prefix. Never use the wildcard at the start of the search as a prefix (i.e. “%sometag”) because this will always result in poor performance.
This is a good article on the subject with ILIKE and indexes:
Index Columns for `LIKE` in PostgreSQL | Niall Burkley's Developer Blog
Searching on other fields would be great too. I have numeric fields for round and minimum level which I need to filter on when a player searches for a team to join. I currently do this in server code and return the filtered list to the user.
This is actually a great solution to the problem. It can be very tricky to provide the right kind of indexes to manage the flexibility required to efficiently scan the groups looking for entries that fit the filter criteria especially as it usually grows more complex over time in games. Your solution to overscan what you need and filter in the RPC function is a good one because the database performance profile will always be great and if you limit the results returned to less than 1000 I imagine you’ll have more than enough to surface a good 20-30 options to the player.
In general we recommend you minimize the use of the raw SQL features of the game server because bad queries can have a huge performance impact on the rest of the system but it can be very very useful when used sparingly.
If you do think we should talk through more how to achieve the more advanced filters you need then give me a detailed example of what sort of filter options you want to provide in the game UI and we can talk it through.
Hope this helps.