Sign In Register

How can we help you today?

Start a new topic
Answered

Read & Update specific field in Document

Hello,


I would like how to access a specific field inside a document.


Given the next document inside a MetaCollection named NewPlayerUnitsDeck:

 

{
  "_id": {
    "$oid": "5a5d295446e0fb0001c7ff5c"
  },
  "InitialUnits": [
    "automagun_u",
    "minir_u",
    "rustyb_u",
    "rush_u",
    "mammoth_u",
    "rustking_u",
    "baited_u",
    "hehe_u"
  ]
}

Once I have


var defaultUnits = Spark.metaCollection('NewPlayerUnitsDeck').find({},{"_id":0});


how do I acces the field InitialUnits to get that list? Can I treat defaultUnits as a GSData like if I was inside Unity and then do defaultUnits .GetStringList("defaultUnits ")?


GSData has several methods like GetString, GetInt, GetIntList etc. but not sure if that works inside cloud code.



Best Answer

Hi Ivan,


In cloud code you can use dot notation to get this:


var defaultUnitsDoc = Spark.metaCollection('NewPlayerUnitsDeck').find({},{"_id":0,"InitialUnits":1});

var defaultUnits = defaultUnitsDoc.InitialUnits;


Regards,

Vinnie




Doing some trial and error tests, I found the way to get a specific field adding "InitialUnits":1:


var defaultUnits = Spark.metaCollection('NewPlayerUnitsDeck').find({},{"_id":0,"InitialUnits":1});


But it still doesn't returns the list of units, it returns the whole block like:

"InitialUnits": [
    "automagun_u",
    "minir_u",
    "rustyb_u",
    "rush_u",
    "mammoth_u",
    "rustking_u",
    "baited_u",
    "hehe_u"
  ]

 

How do I access only the information the field is containing? I would like a raw list of iterable objects like:

"automagun_u",
"minir_u",
"rustyb_u",
"rush_u",
"mammoth_u",
"rustking_u",
"baited_u",
"hehe_u"

 

Answer

Hi Ivan,


In cloud code you can use dot notation to get this:


var defaultUnitsDoc = Spark.metaCollection('NewPlayerUnitsDeck').find({},{"_id":0,"InitialUnits":1});

var defaultUnits = defaultUnitsDoc.InitialUnits;


Regards,

Vinnie



Oh god, didn't know I could use dot notation. That was a bit ashaming sorry, I'm struggling a bit with all this MongoDB thing since it's the first time for me, and I'm used to standard SQL queries.


Thanks Vinnie, now I have a list of the units ID's as I wanted. But I'm now struggling with updating or inserting data to a specific field.


For every new player registered, I want to create a unique document for him in PlayerUnits. So in RegisterResponse I have:


Spark.runtimeCollection('PlayerUnits').insert({ "PlayerID" : Spark.getPlayer().getPlayerId(), "Units" : []});


And it works fine, it generates this document for each new registered player:

{
  "_id": {
    "$oid": "5a5ea5b8d23ed2051ff75881"
  },
  "PlayerID": "5a5ea5a5d23ed2051ff74590",
  "Units": []
}

Now I want to fill that Unit[] List with the default units I have in my List plus some data. I have learned how to iterate through those units, but not sure if I should use Update (since the field Units[] already exist) or Insert to add new objects in that list.


In pseudocode, I would like to do:  

//find the unique PlayerUnits document I just created for this new Player
var newPlayerUnitsDocument = Spark.runtimeCollection('PlayerUnits').findOne({"PlayerID" : Spark.getPlayer().getPlayerId()});

//Iterate through my InitialUnits list
defaultUnitsList.forEach(function(defaultUnit){
    
    newPlayerUnitsDocument.InsertOrUpdate({$set : { "Units" :
        {
            "UnitID" : defaultUnit,
            "UnitLevel" : 1,
            "UnitProgress" : 1,
            "UnitAmmount" : 1
        }
    }})
    
});

Again, Not sure if that needs an Update or an Insert, since the Units[] list is already created but empty.


In the end, the final result I'm trying to achieve (whithout much sucess atm) is a document like this inside PlayerUnits for each new player:


{
  "_id": {
    "$oid": "5a5ea5b8d23ed2051ff75881"
  },
  "PlayerID": "5a5ea5a5d23ed2051ff74590",
  "Units": [
    {
      "UnitID" : "automagun_u",
      "UnitLevel" : 1,
      "UnitProgress" : 1,
      "UnitAmmount" : 1
    },
    {
      "UnitID" : "minir_u",
      "UnitLevel" : 1,
      "UnitProgress" : 1,
      "UnitAmmount" : 1
    },
    {
      "UnitID" : "rustyb_u",
      "UnitLevel" : 1,
      "UnitProgress" : 1,
      "UnitAmmount" : 1
    }
    ]
}

 A bit of guidance would be much appreciated. Not sure if I'm over complicating it or if it could be done in less steps.

I did it! I was missing the $push thing for updating arrays and not overwriting them!


Gosh this feels so different to anything I've done in DataBases before. It's like learning a new language. But I'm starting to fell MongoDB's power!


I will mark your answer as correct Vinnie so you can close the thread.


Here is the final code in case someone in the future has the same problem and reads this:


 

//Get a list of the DefaultUnits to be given to new players
var defaultUnits = Spark.metaCollection('NewPlayerUnitsDeck').findOne({},{"_id":0,"InitialUnits":1});
var defaultUnitsList = defaultUnits.InitialUnits;
 
 //Reference to PlayerUnits collection
 var playerUnitsDocument = Spark.runtimeCollection('PlayerUnits');
 
 //Create a unique document in PlayerUnits for the new player
playerUnitsDocument.insert({ "PlayerID" : Spark.getPlayer().getPlayerId(), "Units" : []});


//Iterate through my new Players DefaultUnits 
defaultUnitsList.forEach(function(defaultUnit){
    
    playerUnitsDocument.update(
        {"PlayerID" : Spark.getPlayer().getPlayerId()},
        {
            $push : { "Units" : //Add the unit plus it's values
                {
                "UnitID" : defaultUnit,
                "UnitLevel" : 1,
                "UnitProgress" : 1,
                "UnitAmmount" : 1
                }
            }
        }
    )
    
});

Not sure if it's the best/optimum way to do it because I feel it's a waste to search for a document in the whole collection each loop inside the update function with the first parameter {"PlayerID" : Spark.getPlayer().getPlayerId()}.


If I have 8 DefaultUnits, it means it's searching 8 times for that document inside PlayerUnits collection. It would be nice to do the search only 1 time, store the reference, and update that referenced document X times without redundant searches.


But hey... it works!

For future reference you can '$push' multiple array elements at once with '$each' like so:

var units = [];
var update = { "$push" : { "Units" : { "$each" : units } } };

   

But in this case you can just set them in the initial document before you insert it like so:

// Get a list of the DefaultUnits to be given to new players
var defaultUnits = Spark.metaCollection('NewPlayerUnitsDeck').findOne({});

// Transform array of defaultUnit ids into array of unit objects
var units = defaultUnits.InitialUnits.map(function(defaultUnit) {
    return {
                "UnitID" : defaultUnit,
                "UnitLevel" : 1,
                "UnitProgress" : 1,
                "UnitAmmount" : 1
     });
 };

var playerUnitsDoc = { 
    "PlayerID": Spark.getPlayer().getPlayerId(),
    "Units": units 
};

Spark.runtimeCollection('PlayerUnits').insert(playerUnitsDoc);



1 person likes this

Hey Ryan Fuller, that works!!


You just optimized my code both in size and performance, awesome!


That .map thing blew my mind a little bit, I will use that function more often, very useful indeed. That $each thing working with lists as a parameter is also extremelly useful. I take notes.


I wish I had someone with experience in mongoDB syntax like you by my side while bashing my head against it in CloudCode. In fact, I already told the GameSparks CM that they should definitely create a Slack or Discord chat. It would be of extreme help for the GameSparks community. Heck, it would even help to Official Devs not to waste time with small little questions and focus on more serious problems/bugs that actually need a forum thread for tracking.


Meanwhile, I have to open whole forum threads to ask simple questions with simple answers like "you can use dot notation and do defaultUnitsDoc.InitialUnits" because I was really stuck. That could be answered in the chat by any member of the community. The chat doesn't even have to "official tech support" (if an official dev is there to help, fine, if not, fine too).


Slack/Discord chat = +healthier +engaged and +knowledgeable community. It's not that hard to understand, come on GameSparks, you can do better!!


1 person likes this

Hey I totally agree this is not the ideal/quickest format. I've been working on a mobile game for over 3 years, and when I started using Gamesparks 2 years ago, I had never used mongoDB once. So I'm glad to pass some of this knowledge on. 


I learned from reading the mongoDB docs which are very extensive and helpful with examples. So for instance, to see all update operators for array fields, the reference is here: link.


I have been looking for Slack/Discord or something similar as well. I have even almost started a Gamesparks subreddit since I have a decent amount of experience and the format is easier to digest than here imo. It feels so frustrating to get stuck on what you know someone with just a littler more experience than you could answer in 0.2s but you agonize over testing it out more yourself or posting a question and waiting 1+ days.


Anyway good luck with whatever you're developing. If you have more mongoDB questions and feel stuck feel free to PM me on reddit (username 'fnayr'). I'm on there daily.

Oh I'm on the same boat then... 5+ years of experience as senior/lead game programmer for some big companies but 0 experience with GameSparks. I just quited my job couple of months ago to start my own company, and learning GameSparks is taking a bit longer than desired. I though that the cloud code was like a custom script language specific for GameSparks or so, but I discovered just yesterday that it's 99% MongoDB´s syntax. With this "new" knowledge my Google searches are much more accurate.


"It feels so frustrating to get stuck on what you know someone with just a littler more experience than you could answer in 0.2s but you agonize over testing it out more yourself or posting a question and waiting 1+ days."


+1000 You nailed my feeling. Nothing more to add. 


Going to contact GameSparks CM again to rise this issue. It's not only for us the users, it's also for the good of GameSparks itself too!


I'm even going to offer myself as a MOD to keep the chat healthy and clean, in case they are afraid of that.


1 person likes this

For any wanderer that might read this whole topic, there seems to be an unofficial Discord chat about GameSparks. It would be nice for people to join while they give an official answer:


https://discord.gg/XVGXRzq

Login to post a comment