@mysql/xdevapi
Version:
MySQL Connector/Node.js - A Node.js driver for MySQL using the X Protocol and X DevAPI.
337 lines (263 loc) • 12.2 kB
Markdown
### Id generation
When adding documents to a collection, if a document does not contain an `_id`, it will be automatically assigned a sequential UUID-like value. One can, however, override this behavior by providing a static `_id` for each document.
#### Using automatically assigned values
```javascript
const mysqlx = require('@mysql/xdevapi');
const docs = [];
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
return session.getSchema('mySchema').createCollection('myCollection');
})
.then(collection => {
return collection.add({ name: 'foo' })
.execute()
.then(() => {
return collection.find()
.execute(doc => docs.push(doc));
})
})
.then(() => {
// the `_id` value is just an example in this case
console.log(docs); // [{ _id: '00005a640138000000000000002c', name: 'foo' }]
});
```
#### Using static values
```javascript
const mysqlx = require('@mysql/xdevapi');
const docs = [];
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
return session.getSchema('mySchema').createCollection('myCollection');
})
.then(collection => {
return collection.add({ _id: 1, name: 'foo' })
.execute()
.then(() => {
return collection.find()
.execute(doc => docs.push(doc));
});
})
.then(() => {
console.log(docs); // [{ _id: 1, name: 'foo' }]
});
```
### Single document CRUD
The connector provides a set of utility methods that can be used to add, remove, replace or retrieve a single specific document via its `_id` property.
Consider a collection `mySchema.myCollection` containing the following documents:
```json
[{
"_id": "1",
"name": "foo"
}, {
"_id": "2",
"name": "bar"
}]
```
The following scenarios are possible.
#### Replacing a single document
If a document with a given `_id` already exists in the database, it can be replaced via the {@link module:Collection#replaceOne|`Collection.replaceOne()`} method.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.replaceOne('1', { name: 'baz', age: 23 })
.then(result => {
console.log(result.getAffectedItemsCount()); // 1
return collection.find()
.execute();
});
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', age: 23 }, { _id: '2', name: 'bar' } ]
});
```
If no such document exists, the method will neither fail nor have any effect.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection')
return collection.replaceOne('3', { name: 'baz', age: 23 })
.then(result => {
console.log(result.getAffectedItemsCount()); // 0
return collection.find()
.execute();
});
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'foo' }, { _id: '2', name: 'bar' } ]
});
```
If the replacement document in the second argument contains an `_id` property and its value is different from the id value provided as the first argument, an error will be reported, regardless of whether documents with either of those ids already exist in the collection or not.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection')
return collection.replaceOne('1', { _id: '2', name: 'baz', age: 23 })
})
.catch(err => {
console.log(err.message); // Replacement document has an _id that is different than the matched document.
});
```
#### Creating or updating a single document
The connector also provides an additional utility method - {@link module:Collection#addOrReplaceOne|`Collection.addOrReplaceOne()`} - that allows to seamlessly either create a document with a given `_id` and properties or automatically replace an existing matching document.
So, if a document with the given `_id` already exists in a collection, the behavior is the same as with {@link module:Collection#replaceOne|`Collection.replaceOne()`}.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.addOrReplaceOne('1', { name: 'baz', age: 23 })
.then(result => {
// the existing row is re-created (leading to two different operations)
// see https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
console.log(result.getAffectedItemsCount()); // 2
return collection.find()
.execute();
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'baz', age: 23 }, { _id: '2', name: 'bar' } ]
});
})
```
If no such document exists, a new one will be created.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.addOrReplaceOne('3', { name: 'baz', age: 23 })
.then(result => {
console.log(result.getAffectedItemsCount()); // 1
return collection.find()
.execute();
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'foo' }, { _id: '2', name: 'bar' }, { _id: '3', name: 'baz', age: 23 } ]
});
});
```
Just like {@link module:Collection#replaceOne|`replaceOne()`}, when calling {@link module:Collection#addOrReplaceOne|`addOrReplaceOne()`}, if the replacement document in the second argument contains an `_id` property and its value is different from the id value provided as the first argument, an error will be reported, regardless of whether documents with either of those ids already exist in the collection or not.
```js
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.addOrReplaceOne('3', { _id: '4', name: 'baz', age: 23 })
})
.catch(err => {
console.log(err.message); // Replacement document has an _id that is different than the matched document.
});
```
When additional unique key constraints exist for a collection, a few additional scenarios are brought up. Assuming, the `name` property has a unique key constraint established by a [auto-generated column](https://dev.mysql.com/doc/refman/8.0/en/create-table-secondary-indexes.html#json-column-indirect-index).
```sql
ALTER TABLE mySchema.myCollection ADD COLUMN name VARCHAR(3) GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(doc, '$.name'))) VIRTUAL UNIQUE KEY NOT NULL
```
Existing documents will be updated with the given properties, provided that there are no unique key constraint violations with other documents.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.addOrReplaceOne('1', { name: 'baz' })
.then(result => {
// the existing row is re-created (leading to two different operations)
// see https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
console.log(result.getAffectedItemsCount()); // 2
return collection.find()
.execute();
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'baz' }, { _id: '2', name: 'bar' } ]
});
});
```
Unique key values themselves can also be updated with the same restrictions.
```javascript
const mysqlx = require('@mysql/xdevapi');
const docs = [];
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.addOrReplaceOne('1', { name: 'foo', age: 23 })
.then(result => {
// the existing row is re-created (leading to two different operations)
// see https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
console.log(result.getAffectedItemsCount()); // 2
return collection.find()
.execute();
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'foo', age: 23 }, { _id: '2', name: 'bar' } ]
});
});
```
Unique key constraint violations will, of course, result in an error.
```javascript
const mysqlx = require('@mysql/xdevapi')
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
return session.getSchema('mySchema').getCollection('myCollection').addOrReplaceOne('1', { name: 'bar' });
})
.catch(err => {
console.log(err.message);
})
```
#### Retrieving a single document
There is also an utility method to retrieve a single document from a collection, given its `id` - `Collection.getOne()`. The method returns a `Promise` which resolves to the document instance (in the form of a literal object), if it exists or `null`, if it does not.
```javascript
const mysqlx = require('@mysql/xdevapi')
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
return session.getSchema('mySchema').getCollection('myCollection').getOne('1');
})
.then(doc => {
console.log(doc); // { _id: '1', name: 'foo' }
});
```
```javascript
const mysqlx = require('@mysql/xdevapi')
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
return session.getSchema('mySchema').getCollection('myCollection').getOne('3');
})
.then(doc => {
console.log(doc); // null
});
```
#### Removing a single document
One can also remove a specific document from a collection given its `id` - `Collection.removeOne()`. If no such document exists, the operation succeeds, but nothing really happens.
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.removeOne('1')
.then(result => {
console.log(result.getAffectedItemsCount()); // 1
return collection.find()
.execute();
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '2', name: 'bar' } ]
});
});
```
```javascript
const mysqlx = require('@mysql/xdevapi');
mysqlx.getSession('mysqlx://localhost:33060/mySchema')
.then(session => {
const collection = session.getSchema('mySchema').getCollection('myCollection');
return collection.removeOne('3')
.then(result => {
console.log(result.getAffectedItemsCount()); // 0
return collection.find()
.execute();
})
})
.then(result => {
console.log(result.fetchAll()); // [ { _id: '1', name: 'foo' }, { _id: '2', name: 'bar' } ]
});
```