# Nk.match\_list() not working with search queries

**URL:** <https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97>\
**Category:** Local Setup\
**Created:** [July 25, 2019, 1:30pm UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97 "2019-07-25T13:30:43Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 25, 2019, 1:30pm UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/1 "2019-07-25T13:30:43Z")

</div>

I’m having trouble with match listing, specifically with search queries as listed here.

> **[Authoritative Multiplayer - Nakama server](https://heroiclabs.com/docs/gameplay-multiplayer-server-multiplayer/#search-query)**

With an empty search query it works and returns matches, however when I add a query it finds nothing.

I know the match label and search query have the correct parameters since:

1. The logger says that `Created match has label visibility=public`,  
which is the value of the `label` argument at the end of `M.match_init` that is returned after init. So the match inits with the correct label, `"visibility=public"`.

2. And also from the log `Recieved query is +label.visibility:public`,  
which is the value of the query being searched for.  
I also also tried force-entering a search query in case there was an encoding issue, but there isn’t.  
The query is `"+label.visibility:public"`.

The exact method call is `nk.match_list(search_limit, isAuthoritative, '', min_size, max_size, s_query)`

I also tried replacing the empty label with nill instead of empty quotes with no difference.

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 25, 2019, 3:04pm UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/2 "2019-07-25T15:04:55Z")

</div>

Don’t know what could have caused that issue.  
But here’s an example from the code we use and it works fine -  
inside `match_init` we return the label like this. Updated the label to your use case -

```auto
function m_h.match_init(context, state)
    nk.logger_info("[match_init] : inside new match init. Pre-state = " .. nk.json_encode(state))
    nk.logger_info("[match_init] : new match id = [" .. context.match_id .. "]")

    local label = {
        visibility = "public"
    }
    local match_label = nk.json_encode(label)

    local tickrate = 1 -- per sec

    return state, tickrate, match_label
end

```

Then for searching matches you could use -

```auto
function s_m.list_matches(context, payload)
    local json = nk.json_decode(payload)

    --[[
        ------------------ fetching from the live tables ---------------------------
        List at most 10 matches, authoritative true, and that
        have between min_size and max_size players currently participating.
    --]]
    local limit = 10
    local authoritative = true
    local min_size = 0
    local max_size = 12

    local visibility = json.visibilty -- this will have value "public"
   
    local filter = "+label.visibility:".. tostring(visibility)
    
    --Searching matches with filter
    local matches_list = nk.match_list(limit, authoritative, nil, min_size, max_size, filter)
    local response = {}

    if(matches_list) then
         local no_of_matches = #matches_list
         nk.logger_info("[search_matches/list_matches] : Found matches Count : " .. no_of_matches)
        --nk.logger_info(nk.json_encode(matches_list))
        
        if(no_of_matches == 0) then
            nk.logger_info("no matches found")
            response["matches"] = nil
        else
            nk.logger_info("matches found")
            response["matches"] = matches_list
        end
    else
        nk.logger_info("no matches found")
        response["matches"] = nil
    end

    return nk.json_encode(response)
end

```

I hope this helps.

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 9:03am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/3 "2019-07-26T09:03:43Z")

</div>

Thank you, it seemed I had misunderstood how the label should be formatted.

The problem was that I was sending a string with the value of literally “visibility=public” since I did not know it was supposed to be an object looking at the docs.

To fix it, now I send a json object from the client with value `{label: {visiblity : "public"}}` as the setup payload for the match, and then on the server I use `nk.json_decode()` in `match_create_rpc()` to save it to the match’s setup state, and then I assign in `M.match_init()` normally by reading it from the match’s setup state.

Here’s some of the code to clarify what is working:

Client Side:

```auto
    async create_public_match(payload = null) {
        var data = payload || { label: { visibility: "public" } };

        var match_id = await multiplayer._create_match(data);

        return match_id;
    }

    async _create_match(match_payload: object) {
        var match_id = await backendManager.send_rpc("create_match_rpc", match_payload);

        if (match_id && match_id.payload && match_id.payload.match_id) {
            console.log("Succesfully created new match.");
            return match_id.payload.match_id;
        } else {
            console.log("Error creating new match.");
            return null;
        }

    }

```

Server Side:

```auto
local nk = require('nakama')

local function create_match(context, payload)
    local modulename = 'match_handler'
    local setupstate = {initialstate = nk.json_decode(payload)}

    local matchid = nk.match_create(modulename, setupstate)

    -- Send notification of some kind
    return nk.json_encode({['match_id'] = matchid, ['setupstate'] = setupstate})
end
nk.register_rpc(create_match, 'create_match_rpc')

local min_size = 0
local max_size = 2
local search_limit = 100
local isAuthoritative = true
local default_search_query = '+label.visibility:public'
local function find_match(search_query)
    print('Searching with recieved query: ' .. search_query)
    local s_query = search_query or default_search_query

    local matches = nk.match_list(search_limit, isAuthoritative, nil, min_size, max_size, s_query)
    if (#matches > 0) then
        table.sort(
            matches,
            function(a, b)
                return a.size > b.size
            end
        )
        return matches[1].match_id
    else
        print('Could not find matching matches.')
        return nil
    end
end

local function quick_find_match(context, payload)
    local found_match_id = find_match(payload and nk.json_decode(payload).search_label)
    nk.logger_info(('Quick find game result is %s'):format(found_match_id))
    return nk.json_encode({['match_id'] = found_match_id})
end

nk.register_rpc(quick_find_match, 'quick_find_match_rpc')

```

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 9:12am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/4 "2019-07-26T09:12:30Z")

</div>

Also if I make ask, what is the purpose of min\_size and max\_size in this method call?

---

<div class="post-metadata">

**Author:** ![novabyte](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/novabyte/32/1324_2.png) [@novabyte](https://forum.heroiclabs.com/u/novabyte)\
**Post date:** [July 26, 2019, 10:32am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/5 "2019-07-26T10:32:20Z")

</div>

@GroovyAntoidDev There’s a bit of history to our match labels. If a label is formatted in the way you’d done in your first example it will **not** be indexed by the matchmaker. Instead it would be used to exact match the input string from game clients. This is why your query was ignored.

You should make the inputs you want to query in a JSON object for it to be indexed by the matchmaker. Thanks to @hdjay0129 for his example on how to do it.

> Also if I make ask, what is the purpose of min\_size and max\_size in this method call?

The min and max size fields are used to filter to matches returned which contain the range of players between those two values. i.e. Find me matches which have at least 1 player in and no more than 12 players. This would be represented with a min\_size of 1 and a max\_size of 12.

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 10:36am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/6 "2019-07-26T10:36:54Z")

</div>

@novabyte It seems the `size` is based on active presences, is it possible to get the total number of players who joined even if they’re offline, since for turn-based games most of the time the players are not both online and they join and disconnect regularly.

If that’s not possible, is it possible to edit the label after creation to indicate whether the match is full or not, or perhaps use the returned data in the match list to get the match state?

Edit: To clarify, what I am trying to do is that games have a 2 player limit, and I register the joined players in the match state and the match will reject joins when it reaches 2 registered players unless they are one of the two who had registered before.

These 2 players have the match id recorded and they can currently seamlessly and perfectly switch from realtime to turn based play depending on whether the opponent is online.

However, I need other players to be able to filter the lobby list to get matches they _can_ join i.e. registered users \< 2, which requires accessing the match state or if possible filtering the match list in a better way.

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 26, 2019, 10:42am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/7 "2019-07-26T10:42:19Z")

</div>

I think you can store the total no of joined players inside the match label and update it according whenever a player join or leave and then call this -  
`"label.total_joined:>" .. min_joined .. " AND label.total_joined:<" .. max_joined`

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 10:43am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/8 "2019-07-26T10:43:23Z")

</div>

@hdjay0129 Thank you, that would indeed fix it, but I could not find info in the docs about where the label is stored after initialization, is it inside the match state or somewhere else?

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 26, 2019, 10:47am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/9 "2019-07-26T10:47:35Z")

</div>

You can use this to update label in game -  
`dispatcher.match_label_update("updatedlabel")`  
more info - [https://heroiclabs.com/docs/gameplay-multiplayer-server-multiplayer/#match-runtime-api](https://heroiclabs.com/docs/gameplay-multiplayer-server-multiplayer/#match-runtime-api)

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 26, 2019, 10:52am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/10 "2019-07-26T10:52:50Z")

</div>

Also, if you only want two players to join the match. Then you can track the no of joined players inside the state and then check for total joined inside match\_joined\_attempt callback to check for your conditions.  
Like this -

```auto
local function match_join_attempt(context, dispatcher, tick, state, presence, metadata)
  -- Presence format:
  -- {
  -- user_id = "user unique ID",
  -- session_id = "session ID of the user's current connection",
  -- username = "user's unique username",
  -- node = "name of the Nakama node the user is connected to"
  -- }
  local accept_user = true
  local reason = ""
  if(state.total_joined == 2) then
    accept_user = false
    reason = "match full"
  end
  return state, accept_user, reason
end

```

EDIT : I think you are already doing this. But just in case.  
Also, I think, it would be better to open another thread for this 😄

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 10:56am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/11 "2019-07-26T10:56:56Z")

</div>

Thanks for that `dispatcher.match_label_update` method! I swear I literally just read the runtime api but I didn’t go past that section.

And also thank you for the second snippet, I am doing exactly that in the `match_join_attempt()` and it works perfectly.

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 26, 2019, 10:58am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/12 "2019-07-26T10:58:56Z")

</div>

Great 👍  
Glad to know it helped

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 10:59am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/13 "2019-07-26T10:59:14Z")

</div>

Isn’t the label an object now, how does this work with a string?

Edit: Ah yeah I guess I should open another thread, but I guess technically we’re still talking about match labels 😃

---

<div class="post-metadata">

**Author:** ![hdjay0129](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/hdjay0129/32/1103_2.png) [@hdjay0129](https://forum.heroiclabs.com/u/hdjay0129)\
**Post date:** [July 26, 2019, 11:01am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/14 "2019-07-26T11:01:08Z")

</div>

I think, we are using label as object on top level but internally it’s still being used as string for backward compatibility.  
@novabyte might know more.

---

<div class="post-metadata">

**Author:** ![novabyte](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/novabyte/32/1324_2.png) [@novabyte](https://forum.heroiclabs.com/u/novabyte)\
**Post date:** [July 26, 2019, 11:49am UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/15 "2019-07-26T11:49:18Z")

</div>

Yes. It’s as @hdjay0129 mentioned. Internally the game server still respects the match label as a string literal but you would store within it a JSON object for it to be indexed by the matchmaker.

---

<div class="post-metadata">

**Author:** ![GroovyAntoidDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/groovyantoiddev/32/39_2.png) [@GroovyAntoidDev](https://forum.heroiclabs.com/u/GroovyAntoidDev)\
**Post date:** [July 26, 2019, 1:04pm UTC](https://forum.heroiclabs.com/t/nk-match-list-not-working-with-search-queries/97/16 "2019-07-26T13:04:40Z")

</div>

Edit: I managed to get it to work, I will post some code here in a few moments and then close this thread :b

Thanks everyone!

Some server-side snippets:  
(Note that these are tiny fragments that are not functional on their own, look at earlier comments in this post and at the docs for a full example of the match handler).

```auto
local function find_match(search_query)
    local s_query = (search_query or default_search_query) .. ' +label.total_joined:<2'
    print('Searching with the query: ' .. s_query)

    local matches = nk.match_list(search_limit, isAuthoritative, nil, min_size, max_size, s_query)

```

```auto
local default_new_match_label = {visibility = 'private'}
function M.match_init(context, setupstate)
    local tickrate = 1 -- per sec
    local g_label = setupstate.initialstate.label or default_new_match_label
    g_label.total_joined = 0

    local gamestate = {
        label = g_label,
        other =properties,
etc...
    }

    return gamestate, tickrate, nk.json_encode(g_label)
end

```

```auto
function M.match_join(context, dispatcher, tick, state, presences)
    for _, presence in ipairs(presences) do
        state.presences[presence.user_id] = presence

        state.label.total_joined = state.label.total_joined + 1
        local new_label = nk.json_encode(state.label)
        print('Match label is now ' .. new_label)
        dispatcher.match_label_update(new_label)

```
