Skip to main content

Database

Basic Concepts

Collection

A collection is a set of documents. You can obtain a reference to a specified collection using db.collection(name). The following operations can be performed on a collection:

TypeInterfaceDescription
WriteaddAdd document (trigger request)
CountcountGet the count of matching documents
ReadgetGet documents in a collection. If a where clause is used to define query conditions, the matching result set will be returned (triggers a request)
ReferencedocGet a reference to the document with the specified id in this collection
Query ConditionswhereFilter matching documents by specifying conditions, which can be used with query operators (eq, gt, in, ...)
skipSkips a specified number of documents, commonly used for pagination by passing an offset value
orderBySorting method
limitLimits the number of documents in the returned result set, with a default value and a maximum value (maximum limit is 1000)
fieldSpecifies the fields to return

Query and update operators are used to specify conditions that fields must satisfy in where, and can be accessed via the db.command object.

Record / Document

A document is a storage unit in a database collection, represented as a json object in cloud development. You can obtain a reference to a document with a specified id in a given collection using db.collection(collectionName).doc(docId). The following operations can be performed on a document:

InterfaceDescription
WritesetOverwrite document
updatePartial update of a document (triggers a request)
removeDelete document (triggers a request)
ReadgetGet document (triggers a request)

Query Command

Query operators are used to construct query conditions. The following operators are all attached to db.command

TypeInterfaceDescription
Comparison OperatoreqField ==
neqField !=
gtField >
gteField >=
ltField <
lteField <=
inField value in array
ninField value not in array
Logical OperatorandIndicates that all specified conditions must be satisfied simultaneously
orIndicates that at least one of the specified conditions must be satisfied

Update Command

Update operators are used to construct update operations. The following operators are all attached to db.command

TypeInterfaceDescription
Update OperatorsetSets a field equal to a specified value
incInstructs the field to increment by a specified value
mulInstructs the field to multiply by a specified value
removeRemove a field
pushAppends elements to the end of an array, supporting passing in either a single element or an array
popRemoves the last element from an array
shiftRemoves the first element from an array. Usage is the same as pop
unshiftAdds elements to the beginning of an array, supports passing in either a single element or an array. Usage is the same as push

Getting the Database Instance

Note: No parameters are required; returns the database instance.

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "xxxx-yyy",
});

const db = app.database();

Getting the Collection Reference

Note: Accepts a name parameter specifying the collection name to be referenced.

// Get the reference of the `user` collection
import cloudbase from "@cloudbase/js-sdk";

const app = cloudbasae.init({
env: "xxxx-yyy",
});

const db = app.database();

const collection = db.collection("user");

Query Operators

eq

Indicates that a field equals a value. The eq operator accepts a literal, which can be number, boolean, string, object, or array.

For example, to filter out all articles published by oneself, besides using the object-passing approach:

const myOpenID = "xxx";
db.collection("articles").where({
_openid: myOpenID,
});

can also use the command:

const _ = db.command;
const myOpenID = "xxx";
db.collection("articles").where({
_openid: _.eq(openid),
});

Note that the eq operator offers greater flexibility than the object approach and can be used to represent cases where a field equals an object, for example:

// This syntax indicates matching both stat.publishYear == 2018 and stat.language == 'zh-CN'
db.collection("articles").where({
stat: {
publishYear: 2018,
language: "zh-CN",
},
});
// This syntax indicates that the stat object equals { publishYear: 2018, language: 'zh-CN' }
const _ = db.command;
db.collection("articles").where({
stat: _.eq({
publishYear: 2018,
language: "zh-CN",
}),
});

neq

Indicates that a field does not equal a value. The neq operator accepts a literal, which can be number, boolean, string, object, or array.

For example, to filter out computers whose brand is not X:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
brand: _.neq("X"),
},
});

gt

The field is greater than the specified value.

For example, to filter out computers with a price greater than 2000:

const _ = db.command;
db.collection("goods").where({
category: "computer",
price: _.gt(2000),
});

gte

The field is greater than or equal to the specified value.

lt

The field is less than the specified value.

lte

The field is less than or equal to the specified value.

in

The field value is within the given array.

To filter out computer products with memory of 8g or 16g:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.in([8, 16]),
},
});

nin

The field value is not in the given array.

To filter out computer products with memory not being 8g or 16g:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.nin([8, 16]),
},
});

and

Means that two or more specified conditions must be satisfied simultaneously.

For example, filter out computer products with memory greater than 4g and less than 32g:

Streaming syntax:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.gt(4).and(_.lt(32)),
},
});

Prefix syntax:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
memory: _.and(_.gt(4), _.lt(32)),
},
});

or

Means that at least one of the specified conditions must be satisfied. For example, filter out computers with a price less than 4000 or 6000-8000:

Streaming syntax:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
price: _.lt(4000).or(_.gt(6000).and(_.lt(8000))),
},
});

Prefix syntax:

const _ = db.command;
db.collection("goods").where({
category: "computer",
type: {
price: _.or(_.lt(4000), _.and(_.gt(6000), _.lt(8000))),
},
});

If you want to perform a cross-field "OR" operation: (e.g., filter out computers with 8g memory OR 3.2 ghz cpu)

const _ = db.command;
db.collection("goods").where(
_.or(
{
type: {
memory: _.gt(8),
},
},
{
type: {
cpu: 3.2,
},
}
)
);

RegExp

Filter based on regular expressions

For example, the following can filter out documents where the version field starts with "digit+s", case-insensitively:

// You can directly use regular expressions
db.collection('articles').where({
version: /^\ds/i
})

// Or
db.collection('articles').where({
version: new db.RegExp({
regexp: '^\\ds' // The regular expression is /^\ds/, after escaping, it becomes '^\\ds'
options: 'i' // i indicates case-insensitive
})
})

Update Command

set

Description: Used to set a field equal to a specified value. This method, compared to passing a plain JS object, has the advantage of being able to specify that a field equals an object.

Sample Code:

// The following method will only update style.color to red, rather than updating style to { color: 'red' }, meaning it does not affect other fields in style
db.collection("todos")
.doc("doc-id")
.update({
style: {
color: "red",
},
});

// The following method updates style to { color: 'red', size: 'large' }
const _ = db.command;
db.collection("todos")
.doc("doc-id")
.update({
style: _.set({
color: "red",
size: "large",
}),
});

inc

Description: Used to indicate that a field increments by a certain value. This is an atomic operation. The advantage of using this operation command instead of reading the data first, then adding to it, and finally writing it back is:

Remarks:

  1. Atomicity: When multiple users write simultaneously, the database increments the field by one for each operation, eliminating the risk of later writes overwriting earlier ones.
  2. Reduces one network request: eliminates the need for read-before-write operations.

The same applies to the subsequent mul instruction.

Sample Code:

const _ = db.command;

db.collection("user")
.where({
_openid: "my-open-id",
})
.update({
count: {
favorites: _.inc(1),
},
})
.then(function (res) {});

mul

Description: Used to multiply a field by a specified value.

remove

Update command. Used to indicate the deletion of a field. For example, when a user deletes the rating in one of their product reviews:

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
rating: _.remove(),
})
.then(function (res) {});

push

Appends elements to the end of an array, supporting passing in either a single element or an array.

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
// users: _.push('aaa')
users: _.push(["aaa", "bbb"]),
})
.then(function (res) {});

pop

Removes the last element from an array.

const _ = db.command;

db.collection("comments")
.doc("comment-id")
.update({
users: _.pop(),
})
.then(function (res) {});

unshift

Adds elements to the beginning of an array, supports passing in either a single element or an array. Usage is the same as push

shift

Removes the first element from an array. Usage is the same as pop

Build query conditions

Supports operations such as where(), limit(), skip(), orderBy(), get(), update(), field(), count(), and more.

The request is only actually sent when get() or update() is called.

where

Description: Sets the filter conditions. where can accept an object as a parameter, indicating to filter out documents that have the same key-value pairs as the passed object.

Input parameters: None

For example, to filter out all products of computer type with 8g memory:

db.collection("goods").where({
category: "computer",
type: {
memory: 8,
},
});

To express more complex queries, you can use advanced query commands, for example, to filter out all computer products with memory greater than 8g:

const _ = db.command; // Get the command
db.collection("goods").where({
category: "computer",
type: {
memory: _.gt(8), // which means greater than 8
},
});

limit

Description: Specifies the upper limit for the number of query result sets.

Input parameters:

ParameterTypeRequiredDescription
-IntegerYesLimits the displayed number (the maximum limit is 1000)

Use Case

collection
.limit(1)
.get()
.then(function (res) {});

skip

Description: Specifies to return query results starting after a specified index, commonly used for pagination. Input parameters:

ParameterTypeRequiredDescription
-IntegerYesNumber of entries to skip

Example Code

collection
.skip(4)
.get()
.then(function (res) {});

field

Description: Specifies the fields to be returned in the documents within the query results.

Input parameters:

ParameterTypeRequiredDescription
-objectYesFields to filter: set to false to exclude, true to include.

Example Code

collection.field({ age: true });

Note: The field method accepts a required object to specify the fields to be returned. Each key in the object represents a field to include or exclude, and the value (true|false or 1|-1) indicates whether to return the field.

orderBy

Description: Specifies the sort criteria for queries.

Input parameters:

ParameterTypeRequiredDescription
fieldstringYesField to sort by
orderTypestringYesSort order: asc (ascending) or desc (descending)

Note: The method accepts a required string parameter fieldName to define the field to sort by, and a string parameter order to specify the sort direction. order can only be set to asc or desc.

To sort nested fields, use dot notation to connect them. For example, style.color represents the nested color field within the style field.

It also supports sorting by multiple fields. Simply call orderBy multiple times. The sort order for multiple fields will follow the sequence of the orderBy calls.

Example Code

collection
.orderBy("name", "asc")
.get()
.then(function (res) {});

add

1. Interface Description

Function: Insert a document

Interface declaration: collection.add(object: Object): Promise<Object>

Note: The set method can also be used to add documents. Please refer to the set method in the document update section.

Example:

2. Input Parameters

ParameterTypeRequiredDescription
dataobjectYes{_id: '10001', 'name': 'Ben'} and _id is optional

3. Output Parameters

FieldTypeRequiredDescription
codestringNoStatus code, not returned if the operation is successful
messagestringNoError description

4. Sample Code

collection
.add({
name: "Ben",
})
.then((res) => {})
.catch((e) => {});

get

1. Interface Description

Interface Function: Get the database query result.

Interface declaration: get(): Promise<Object>

Note: If no limit is specified in get(), the first 100 records are returned by default, and a maximum of the first 100 records will be returned.

2. Input Parameters

Null

3. Output Parameters

FieldTypeRequiredDescription
codestringNoStatus code, not returned if the operation is successful
messagestringNoError description
dataobjectNoQuery result
requestIdstringYesRequest ID, used for error troubleshooting

4. Sample Code

collection
.where({
category: "computer",
type: {
memory: 8,
},
})
.get()
.then((res) => {})
.catch((e) => {});

count

1. Interface Description

Interface Function: Get the count of database query results.

Interface declaration: cout(): Promise<Object>

2. Input Parameters

Null

3. Output Parameters

FieldTypeRequiredDescription
codestringNoStatus code, not returned if the operation is successful
messagestringNoError description
totalIntegerNoCount result
requestIdstringNoRequest ID, used for error troubleshooting

4. Sample Code

db.collection("goods")
.where({
category: "computer",
type: {
memory: 8,
},
})
.count()
.then(function (res) {
const total = res.total; // The number of documents that meet the criteria
});

remove

1. Interface Description

Function: Delete a document

Interface declaration: remove(): Promise<Object>

2. Input Parameters

None

3. Output Parameters

FieldTypeRequiredDescription
codestringNoStatus code, not returned if the operation is successful
messagestringNoError description
deletedInteterNoNumber of deleted documents
requestIdstringYesRequest ID, used for error troubleshooting

4. Sample Code

Method 1: Delete by specifying the document ID

collection.doc(_id).remove()

collection
.doc("xxx")
.remove()
.then((res) => {
console.log(`${res.deleted} docs deleted`);
})
.catch((e) => {});

Method 2: Query documents by condition and then delete them in batch directly

// Delete documents where field a is greater than 2
collection
.where({
a: _.gt(2),
})
.remove()
.then(function (res) {
const deleted = res.deleted;
});

update / set

1. Interface Description

Interface Function: Update documents

Interface Declaration:

update(object: <Object\>): Promise<Object>

set(object: <Object\>): Promise<Object>

Note: Both update and set can be used to update documents. The difference is that the set method creates a new document when the target document doesn't exist, while the update method does nothing and returns updated as 0.

2. Input Parameters

FieldTypeRequiredDescription
-<Object>YesDefinition of the replacement document

3. Output Parameters

FieldTypeRequiredDescription
codestringNoStatus code, not returned if the operation is successful
messagestringNoError description
updatedIntegerNoNumber of affected documents
upsertedIdstringNoid of the inserted document
requestIdstringYesRequest ID, used for error troubleshooting

4. Sample Code

Update the specified document

// Update the specified document
collection
.doc("doc-id")
.update({
name: "Hey",
})
.then(function (res) {});

Update the document, or create it if it does not exist

// Update a single document
collection
.doc("doc-id")
.set({
name: "Hey",
})
.then(function (res) {});

// Batch update documents
collection
.where({ name: _.eq("hey") })
.update({
age: 18,
})
.then(function (res) {});

GEO Geographic Location

Note: If you need to search fields of geolocation type, you must create a geolocation index.

GEO Data Type

Point

Used to represent a geographical location point, uniquely identifying a point using latitude and longitude. This is a special data storage type.

Signature: Point(longitude: number, latitude: number)

Example:

new db.Geo.Point(longitude, latitude);

LineString

Used to represent a geographic path, which is a line segment composed of two or more Points.

Signature: LineString(points: Point[])

Example:

new db.Geo.LineString([
new db.Geo.Point(lngA, latA),
new db.Geo.Point(lngB, latB),
// ...
]);

Polygon

Used to represent a geographical polygon (with or without holes), which is a geometric shape composed of one or more closed-loop LineStrings.

A Polygon formed by a single ring is a polygon without holes, while one formed by multiple rings is a polygon with holes. For a polygon (Polygon) composed of multiple rings (LineString), the first ring is the outer ring and all others are inner rings (holes).

Signature: Polygon(lines: LineString[])

Example:

new db.Geo.Polygon([
new db.Geo.LineString(...),
new db.Geo.LineString(...),
// ...
])

MultiPoint

Used to represent a collection of multiple Points.

Signature: MultiPoint(points: Point[])

Example:

new db.Geo.MultiPoint([
new db.Geo.Point(lngA, latA),
new db.Geo.Point(lngB, latB),
// ...
]);

MultiLineString

Used to represent a collection of multiple geographic paths LineStrings.

Signature: MultiLineString(lines: LineString[])

Example:

new db.Geo.MultiLineString([
new db.Geo.LineString(...),
new db.Geo.LineString(...),
// ...
])

MultiPolygon

Used to represent a collection of multiple geographic Polygons.

Signature: MultiPolygon(polygons: Polygon[])

Example:

new db.Geo.MultiPolygon([
new db.Geo.Polygon(...),
new db.Geo.Polygon(...),
// ...
])

GEO operators

geoNear

Find documents with field values near a given point, sorted from nearest to farthest.

Signature:

db.command.geoNear(options: IOptions)

interface IOptions {
geometry: Point // Geographic location of a point
maxDistance?: number // Optional. Maximum distance in meters.
minDistance?: number // Optional. Minimum distance in meters.
}

Example:

db.collection("user").where({
location: db.command.geoNear({
geometry: new db.Geo.Point(lngA, latA),
maxDistance: 1000,
minDistance: 0,
}),
});

geoWithin

Find documents with field values within the specified Polygon / MultiPolygon, without sorting.

Signature:

db.command.geoWithin(IOptions);

interface IOptions {
geometry: Polygon | MultiPolygon; // Geographic location
}

Example:

// A closed area
const area = new Polygon([
new LineString([
new Point(lngA, latA),
new Point(lngB, latB),
new Point(lngC, latC),
new Point(lngA, latA),
]),
]);

// Search for users whose location field is within this area
db.collection("user").where({
location: db.command.geoWithin({
geometry: area,
}),
});

geoIntersects

Find documents where the field value intersects the given geographic shape.

Signature:

db.command.geoIntersects(IOptions);

interface IOptions {
geometry:
| Point
| LineString
| MultiPoint
| MultiLineString
| Polygon
| MultiPolygon; // Geographic area
}

Example:

// A path
const line = new LineString([new Point(lngA, latA), new Point(lngB, latB)]);

// Search for users whose location intersects this path
db.collection("user").where({
location: db.command.geoIntersects({
geometry: line,
}),
});

Database real-time push

Watch for documents matching the query conditions in the specified collection and obtain detailed change information of the documents through the onchange callback. (The where parameter is the query condition. Refer to Query Documentation)

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "tcbenv-mPIgjhnq",
});
const db = app.database();
const _ = db.command;
const collection = db.collection("collName"); // collName should be the collection name in the current environment

let ref = collection.where({ test: _.gt(0) }).watch({
onChange: (snapshot) => {
console.log("Received snapshot**********", snapshot);
},
onError: (error) => {
console.log("Received error**********", error);
},
});

Watching a single document can also be done using the form doc('docId').watch()

let ref = collection.doc("one docId").watch({
onChange: (snapshot) => {
console.log("Received snapshot**********", snapshot);
},
onError: (error) => {
console.log("Received error**********", error);
},
});

Manually close the listener, and the current listener will no longer receive push notifications.

ref.close().then((result) => {
// The listener has been closed
});