Creating a mirror of your player system collection using the Game Data Service (GDS) will allow you to create a searchable version of your playerbase. Searches cannot be applied to the player collection directly because it is a protected system collection.

If your game requires a significant amount of custom player data to be stored, you can also put this in the mirrored GDS document.


Note: if your custom player data is minimal, then the best approach would be to store it in the player's script or private data.


Config

The first thing you'll need to do is create a Data Type to store the existing player fields you wish to be able to search on and (optionally) your custom player data. Add indexes for the fields you'll be querying:




Next, you'll need to create an event (or events) for querying this data type, adding an attribute for the field you're going to use for querying:



Cloud Code


The first piece of cloud code needed is in your RegistrationRequest. Here you just need to take any custom fields being sent in the RegistrationRequests's scriptData and send it on to the RegistrationResponse to be added to the playerData GDS document. This step isn't needed if you're not adding any custom data.


//send received email address on to response
Spark.setScriptData("email", Spark.getData().scriptData.email);


Next, in the RegistrationResponse, retrieve the player document fields you wish to be able to search on, along with any custom player data passed in from the RegistrationRequest above and save it using GDS. Using the newly created player's id as the GDS document id makes it easy to associate a GDS player data document with the player's corresponding system collection document.


//In the event of registration failure (e.g. userName already taken) exit script
var data = Spark.getData();
if(data.error){
    Spark.exit();
}

//Create a gds document to store this player's details
var player = Spark.getPlayer();
Spark.getGameDataService().
    createItem("playerData", Spark.getPlayer().getPlayerId()).
    setData({
        "userName":player.getUserName(),
        "displayName":player.getDisplayName(),
        "email":data.scriptData.email
    }).
    persistor().persist();


The final piece of cloud code needed is for the search event itself - in this example, the findPlayerByUserName event. This script will query the GDS collection for a record with a userName matching the one provided by the client, then return some player data made up of a combination of the data held in GDS, and that stored on the player system collection document itself.


//query gds for custom player data
var gds = Spark.getGameDataService();
var query = gds.S("userName").eq(Spark.getData().userName.toLowerCase());
var result = gds.queryItems("playerData", query).cursor();

//if no matching userName found, return message and exit script
if(!result.hasNext()){
    Spark.setScriptData("player", "no matching player found");
    Spark.exit();
}

//process the result, retrieve required data and return to client
var res = result.next();
var playerData = res.getData();
var player = Spark.loadPlayer(res.getId());
Spark.setScriptData("player", {
  "displayName":playerData.displayName,
  "email":playerData.email,
  "vGoods":player.getVirtualGoods(),
  "achievements":player.getAchievements(),
  "currencyBalances":player.getAllBalances()
});


If you intend to use the ChangeUserDetailsRequest in your game to allow users to change their userNames, and so on, you will also need to update the player's associated GDS document in the case of a name change. You can do this in the ChangeUserDetailsResponse script with:


//exit if the change request failed
var data = Spark.getData();
if(data.error){
    Spark.exit();
}

//retrieve the player's GDS document
var player = Spark.getPlayer();
var gds = Spark.getGameDataService();
var playerItem = gds.getItem("playerData", player.getPlayerId());

//update the document's data and re-persist it to the database
var playerData = playerItem.document().getData();
playerData.userName = player.getUserName();
playerData.displayName = player.getDisplayName();
playerItem.document().persistor().persist();