All Collections
Features and APIs
Custom Entities -- a scalable and flexible app data storage and querying solution
Custom Entities -- a scalable and flexible app data storage and querying solution

app data, user data, custom entity

Jason Liang avatar
Written by Jason Liang
Updated over a week ago

Note - Custom Entities are a Plus Plan feature. Choose from one of many Plus Plans (including the $5 / month Development Plus Plan) to gain access.


Custom Entities is the super-charged versions of Global and User Entities. It comes with all the features of our standard entity systems (with ownership, ACL, time-to-live, and concurrency versioning) - plus support for Custom Indexes (i.e. much faster!) and Deployment Migration (i.e. more convenient!). We especially recommend them for cases where you have large datasets with many ways in which that data will be accessed. 

Custom Entities is similar to both Global Entities and User Entities - with some definite performance advantages - due to the fact that you can create custom indexes for them. Indexes support the efficient execution of queries. Without them, the database must scan every document in a collection to select those that match the query statement. If an appropriate index exists for a query, the database can use the index to narrow down the number of documents it must inspect.

To achieve these benefits, you must "define" your Custom Entities ahead-of-time - that's where we attach the index meta-data and such. By comparison, Global Entities and User Entities are essentially "untyped".

Here's the key thing - there are two major classifications of Custom Entities - those that are "owned" (i.e. owned by users) and "unowned".

Unowned Custom Entities are very much like Global Entities (specifically what we refer to as System Entities - which are the property of the app and not a specific user), it also includes deployment app data migration support - so you can easily push app data updated from development to production.

Owned Custom Entities, however, are very much like User Entities, you get all the same concepts as Privacy (they are private to individual players - controlled by ACL), concurrency versioning, etc.

You can even view the entities owned by a player within User Monitoring - which is of course very convenient (and feels very much like User Entities).

That said - you can also view the entire Owned Custom Entity collection at the Global Monitoring level - which can be helpful if you want to search for all players that have reached level 40 or something. This is something that cannot be done with User Entities. 

In the grand scheme of things, unowned Custom Entities are much better than Global Entities. And owned Custom Entities are definitely better than User Entities.

Design Portal

The following Portal Pages allow you easily manipulate Custom Entities:

  • Design | Cloud Data | Custom Entities - allow you to define Custom Entities, their Custom Indexes, and even handy JSON templates for creating new entities.

  • Montoring | Global Monitoring | Custom Entities - View and edit all entity collections - with full search and Import/Export functionality

  • Monitoring | User Monitoring | Custom Entities - Easily view/edit the entities owned by a specific user

Create a Custom Entity

Step 1: Create a Custom Entity Type if don’t have one or want to create a new one: click the [+ Create Entity Type] button on Design | Cloud Data | Custom Entity collections page, enter Entity Type Name (required) and Identifier (optional), check the Owned checkbox if want the instance of this entity must be owned by users (note, once set, cannot be edited later) and check the Migrate checkbox if want this collection can be migrated during a deploy/export.

Note: The above operations can be achieved from brainCould API call SysCreateCollection() as well.

Step 2: Add a custom entity to the created collection type by clicking [+Create Entity] button on the Monitoring | Global Monitoring | Custom Entities page, enter the data inside the Data text box. Set the ACL and TTL (optional, if leave it blank, the default value -- Never Expired will be set) value respectively.

Note: The above operations can be achieved from brainCould API call SysCreateEntity() as well.

Retrieve Custom Entities

Then you can use these custom indexes as searchCriteria to quickly scan your data collection, also can use indexes under sortCriteria for sorting as well by calling GetEntityPage() API.

Add indexes

Once an Entity Type is created, click Configure under Actions caret-down button to open the Detail page, then click [+Add Index] to add an index for this collection. Add the field name (indexed keys) and each key's direction (i.e. 1 or -1 ) pair inside the text box of Keys, and add some options (i.e. index properties, such as sparse, TTL, case insensitive) to the index you are adding inside the text box of Options. The commonly used index types in brainCloud include Single Field Indexes and Compound Indexes (Compound indexes can support queries that match on multiple fields). 

Note: The option of background is set to true by default since this is the only safe way to create an index when the system is live.

Note: The above operations can be achieved from brainCould API call SysCreateIndex() as well.

Note: After creating indexes, you can run the SysListIndexes() to verify all the indexes exist in the specific custom collection.

  • Example of creating Single Field Indexes with a TTL option setting

Note: A special TTL index property supports the implementation of TTL collections. This index option is used with a timestamp field, such as “createdAt”, “expireAt”, specifies the expireAfterSeconds value to set the expiration time to be a certain time frame after the time specified by the timestamp.

  • Example of creating Compound Indexes (querying your collection by referring the name after creation)

Note: The order of the fields listed in a compound index is important. For the example above, the index will contain references to documents sorted first by the values of the name field and, within each value of the name field, sorted by values of the position field. In addition to supporting queries that match on all the index fields, compound indexes can support queries that match on the prefix of the index fields.


Data transition from Global Entities

Custom Entity data is structured very similarly to Global Entities - which allows existing users of Global Entity functionality to easily transfer to Custom Collections functionality.

Important difference - Custom Entities objects do not have an entityIndexedId object. Keep this in mind if you are migrating your Global Entities to Custom Entities.

data transition from Global Entities to Custom Entities

Step 1: Browse to Monitoring | Global Monitoring | Global Entities page, choose a single entity type from the Filter by Type selector, click [Bulk Actions] and select a format under Export All, a JSON object file will be download to your local machine. The file name will be like XGE_12832_ALL_2020-04-16-10-30_raw.json if you choose the Raw JSON Object file.

Step 2: Then go to Monitoring | Global Monitoring | Custom Entities page, select one Entity Type (collection) which you want to import data to from the Custom Entities type list and click View Entities under Actions caret-down button to open the Entities view page, then click [Bulk Actions] and select the same format accordingly under Import.

Step 3: Then upload the JSON file which you exported from Global Entities to here.

Step 4: Data transition is DONE! The Global Entities are transferred to Custom Entities and keep the same attributes (i.e. ACL, time-to-live, and concurrency versioning…) even using the same Entity ID.

Note: There is a limitation for data transferring from Global Entities to Custom Entities through the above operations. It limits to one Entity Type per importing, even though the Global Entities contains more than one types, only one type of entities can be processed, due to the above import operation is under one specific Custom Entities type.

Data Transition from User Entities

Did this answer your question?