> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quickblox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Objects

> Learn how to store and sync data with QuickBlox key-value storage.

Custom Objects module provides flexibility to define any data structure (schema) you need, build one-to-many relations between schemas and control permissions for all operations made on data. Schema is defined in QuickBlox Dashboard.

There are two key concepts in Custom Objects:
\- **Class** represents your schema and contains field names and types.
\- **Record** represents the data you put into your schema.

**Class** and **Record** are similar to table and row in relational database. Every class in Custom Object module comes with five mandatory predefined fields: `_id`, `user_id`, `parent_id`, `created_at`, and `updated_at`.

Allowed data types: **Integer** (or Array of Integer); **String** (or Array of String); **Float** (or Array of Float); **Boolean** (or Array of Boolean); **Location** (Array of \[\< longitude >, \< latitude >]); **File**; **Date**.

Visit [Key Concepts](/docs/key-concepts) page to learn the most important QuickBlox concepts.

## Before you begin

1. Register a [QuickBlox account](https://admin.quickblox.com/signin). This is a matter of a few minutes and you will be able to use this account to build your apps.
2. Configure QuickBlox SDK for your app. Check out [Setup](/sdks/react-native-setup) page for more details.
3. Create a user session to be able to use QuickBlox functionality. See [Authenfication](/sdks/react-native-authentication) page to learn how to do it.

## Create class

To start using Custom Objects module, create a class:

1. Go to [QuickBlox Dashboard](https://admin.quickblox.com/signin).
2. Follow **Custom => Add => Add new class** direction. As a result, **Add new class** popup will appear.
3. Enter a class name, add any fields you want.
   <img src="https://mintcdn.com/quickblox/e8BObhqG0WJty0gE/images/51f19c2-react-custom-add-filed.png?fit=max&auto=format&n=e8BObhqG0WJty0gE&q=85&s=2543036791e80ed409d8b1684012ec97" alt="1454" width="1454" height="647" data-path="images/51f19c2-react-custom-add-filed.png" />
4. Click **Create class button** to create a new class.
   <img src="https://mintcdn.com/quickblox/blsYQNp-sI61UYaV/images/0b58138-react-custom-fields.png?fit=max&auto=format&n=blsYQNp-sI61UYaV&q=85&s=d0f423e1fb1ea17874a19bbc070f1d6a" alt="1690" width="1690" height="371" data-path="images/0b58138-react-custom-fields.png" />

## Create records

To create a single object, use the code snippet below.

```JavaScript JavaScript theme={null}
const customObject = {
  className: 'RNCustomObject2',
  fields: {
    text: 'Lorem ipsum dolor sit amen',
    version: 7,
    tags: [ '#test', '#customobjects', '#quickblox-react-native-sdk'],
    friendsIds: [ 12345, 12346, 12347 ]
  }
};

QB.objects
  .create(customObject)
  .then(function (cObject) { /* custom object created successfully */ })
  .catch(function (e) { /* handle error */ })
```

To create multiple objects, use the code snippet below.

```JavaScript JavaScript theme={null}
const customObjects = {
  className: 'RNCustomObject2',
  objects: [{
    tags: [ '#test', '#customobjects', '#quickblox-react-native-sdk'],
    text: 'Lorem ipsum dolor sit amen 1',
    version: 1500
  }, {
    friendsIds: [],
    tags: [ '#test', '#customobjects', '#quickblox-react-native-sdk'],
    text: 'Lorem ipsum dolor sit amen 2',
    version: 1001
  }, {
    tags: [ '#test', '#customobjects', '#quickblox-react-native-sdk'],
    text: 'Lorem ipsum dolor sit amen 3',
    version: 13
  }]
};

QB.objects
  .create(customObjects)
  .then(function (cObjects) { /* custom objects created successfully */ })
  .catch(function (e) { /* handle error */ })
```

## Retrieve records by IDs

To get records with a particular record ID, use the `getByIds()` method. Set the record ID using the `objectsIds` field of the `query` object. Go over [Sort operators](/sdks/react-native-custom-objects#sort-operators) and [Search operators](/sdks/react-native-custom-objects#search-operators) sections to learn about filters and search operators you can use to retrieve records.

```JavaScript JavaScript theme={null}
const query = {
  className: 'RNCustomObject2',
  objectsIds: ['5d4175afa0eb4715cae5b63f']
};

QB.objects
  .getByIds(query)
  .then(function (results) { /* records found by IDs */ })
  .catch(function (e) { /* handle error */ })
```

The `getByIds()` method accepts one argument of the object type that has the following fields:

| Fields     | Required | Description                    |
| ---------- | -------- | ------------------------------ |
| className  | yes      | Name of a custom object class. |
| objectsIds | yes      | Custom objects IDs.            |

## Retrieve records

You can search for records of a particular class. The request below will return records of the `RNCustomObject2` class, with the `value` greater than `1000`, sorted by the `created_at` field in descending order.

```JavaScript JavaScript theme={null}
const query = {
  className: 'RNCustomObject2',
  filter: {
    field: 'version',
    operator: QB.objects.OBJECTS_SEARCH_OPERATOR.FOR_TYPE.INTEGER.GTE,
    value: '1000'
  },
  sort: {
    ascending: false,
    field: 'created_at'
  },
  limit: 5,
  skip: 5
};

QB.objects
  .get(query)
  .then(function (results) { /* records found */ })
  .catch(function (e) { /* handle error */ })
```

The method `get()` method accepts one argument of the object type with the following fields:

| Field     | Required | Description                                                                                 |
| --------- | -------- | ------------------------------------------------------------------------------------------- |
| className | yes      | A name of a custom object class.                                                            |
| filter    | no       | Specifies filtering criteria for the field.                                                 |
| sort      | no       | Specifies sorting criteria for the field.                                                   |
| skip      | no       | Skip N records in search results. Useful for pagination. Default (if not specified): **0**. |
| limit     | no       | Limit search results to N records. Useful for pagination. Default value: **100**.           |

If you want to retrieve only records updated after some specific date time and order the search results, you can apply operators. Thus, you can apply [search](/sdks/react-native-custom-objects#search-operators) and [sort](/sdks/react-native-custom-objects#sort-operators) operators to the list of records on the page so that it is easier to view specific records.

### Search operators

You can use search operators to get more specific search results. The request below will return records of the `Appointment` class by the `priority` field with the value less than `1`, sorted in descending order by the `updated_at` field.

```JavaScript JavaScript theme={null}
const query = {
  className: "Appointment",
  filter: {
    field: "priority",
    operator: QB.objects.OBJECTS_SEARCH_OPERATOR.FOR_TYPE.INTEGER.LT,
    value: "1",
  },
  sort: {
    ascending: false,
    field: "updated_at",
  },
};

QB.objects
  .get(query)
  .then(function (results) {
    /* records found */
  })
  .catch(function (e) {
    /* handle error */
  });
```

Look at `QB.objects.OBJECTS_SEARCH_OPERATOR` object to find out what search operators you can use. It contains several operators separated by value type. Here are the search operators that you can use to search for the exact data that you need.

| Search operators | Applicable to types             | Description                                          |
| ---------------- | ------------------------------- | ---------------------------------------------------- |
| lt               | integer, float                  | **Less Than** operator.                              |
| lte              | integer, float                  | **Less Than** or **Equal** to operator.              |
| gt               | integer, float                  | **Greater Than** operator.                           |
| gte              | integer, float                  | **Greater Than** or **Equal** to operator.           |
| ne               | integer, float, string, boolean | **Not Equal** to operator.                           |
| in               | integer, float, string          | **IN** array operator.                               |
| or               | integer, float, string          | All records that contain a value 1 **or** value 2.   |
| nin              | integer, float, string          | Not **IN** array operator.                           |
| all              | array                           | **ALL** are contained in array.                      |
| ctn              | string                          | All records that **contain** a particular substring. |

### Sort operators

You can use sort operators to order the search results. The request below will return 10 records of the `Appointment` class sorted in descending by the `priority` field.

```JavaScript JavaScript theme={null}
const query = {
  className: "Appointment",
  sort: {
    ascending: false,
    field: "priority",
  },
  limit: 10,
};

QB.objects
  .get(query)
  .then(function (results) {
    /* records found */
  })
  .catch(function (e) {
    /* handle error */
  });
```

Here are the sort options that you can use to order search results.

| Sort options | Applicable to types | Description                                                             |
| ------------ | ------------------- | ----------------------------------------------------------------------- |
| ascending    | All types           | Sort results in the ascending order by setting the ascending as true.   |
| decsending   | All types           | Sort results in the descending order by setting the ascending as false. |

## Update records

You can update a single record using the code snippet below.

```JavaScript JavaScript theme={null}
const payload = {
  className: customObject.className,
  id: customObject.id,
  fields: {
    text: "Lorem ipsum dolor sit amen UPDATED",
    tags: {
      operator: QB.objects.OBJECTS_UPDATE_OPERATOR.FOR_TYPE.ARRAY.ADD_TO_SET,
      value: "#update",
    },
    friendsIds: {
      operator: QB.objects.OBJECTS_UPDATE_OPERATOR.FOR_TYPE.ARRAY.PULL,
      pullFilter: QB.objects.PULL_FILTER.IN,
      value: currentUser.id,
    },
    version: {
      operator: QB.objects.OBJECTS_UPDATE_OPERATOR.FOR_TYPE.INTEGER.INC,
      value: "1",
    },
  },
};

QB.objects
  .update(payload)
  .then(function (updated) {
    /* custom object updated successfully */
  })
  .catch(function (e) {
    /* handle error */
  });
```

You can update multiple records using the code snippet below.

```JavaScript JavaScript theme={null}
const payload = {
  className: object1.className,
  objects: [
    {
      id: object1.id,
      fields: {
        text: `Lorem ipsum dolor sit amen UPDATED 123`,
        tags: ["#update"],
      },
    },
    {
      id: object2.id,
      fields: {
        friendsIds: [1001001, 1001010],
        version: 1250,
      },
    },
  ],
};

QB.objects
  .update(payload)
  .then(function (updated) {
    /* items updated successfully */
  })
  .catch(function (e) {
    /* handle errror */
  });
```

## Delete records

To delete a single record, use the code snippet below.

```JavaScript JavaScript theme={null}
const query = {
  className: object.className,
  ids: object.id,
};

QB.objects
  .remove(query)
  .then(function () {
    /* removed successfully */
  })
  .catch(function (e) {
    /* handle error */
  });
```

To delete multiple records, use the code snippet below.

```JavaScript JavaScript theme={null}
const query = {
  className: object1.className,
  ids: [object1.id, object2.id],
};

QB.objects
  .remove(payload)
  .then(function () {
    /* removed successfully */
  })
  .catch(function (e) {
    /* handle error */
  });
```

## Relations

It is possible to create a relation between objects of **two different classes** via `_parent_id` field.

For example, we have the class **Rating** that contains `score`, `review`, and `comment` fields. We also have a **Movie** class. So we can create a record of class **Rating** that will point to the record of the class **Movie** via its `_parent_id` field, so the `_parent_id` field will contain the ID of record from class **Movie**.

<Warning>
  This is not a simple soft link. This is actually a **hard link**. When you delete the **Movie** class record then all its children (records of class **Rating** with `_parent_id` field set to the **Movie** class record ID) will be automatically **deleted** as well.
</Warning>
