Beta Draft: 2016-08-16

Chapter 4 Working with Collections

Table of Contents

4.1 Basic CRUD Operations on Collections
4.2 Collection Objects
4.2.1 Creating a Collection
4.2.2 Working with Existing Collections
4.3 Collection CRUD Function Overview

The following section explains how to work with Collections, how to use CRUD operations on Collections and return Documents.

4.1 Basic CRUD Operations on Collections

Working with collections of documents is straight forward when using the X DevAPI. The following examples show the basic usage of CRUD operations when working with documents.

After establishing a connection to a MySQL Server, a new collection that can hold JSON documents is created and several documents are inserted. Then, a find operation is executed to search for a specific document from the collection. Finally, the collection is dropped again from the database. The example assumes that the test schema exists and that the collection my_collection does not exist.

MySQL Shell JavaScript Code

// Connecting to MySQL Server and working with a Collection

var mysqlx = require('mysqlx').mysqlx;

// Connect to server
var mySession = mysqlx.getSession( {
host: 'localhost', port: 33060,
dbUser: 'mike', dbPassword: 's3cr3t!'} );

var myDb = mySession.getSchema('test');

// Create a new collection 'my_collection'
var myColl = myDb.createCollection('my_collection');

// Insert documents
myColl.add({name: 'Sakila', age: 15}).execute();
myColl.add({name: 'Susanne', age: 24}).execute();
myColl.add({name: 'Mike', age: 39}).execute();

// Find a document
var docs = myColl.find('name like :param1 AND age < :param2').limit(1).
        bind('param1','S%').bind('param2',20).execute();

// Print document
print(docs.fetchOne());

// Drop the collection
session.dropCollection('test','my_collection');

MySQL Shell Python Code

# Connecting to MySQL Server and working with a Collection

import mysqlx

# Connect to server
mySession = mysqlx.getSession( {
'host': 'localhost', 'port': 33060,
'dbUser': 'mike', 'dbPassword': 's3cr3t!'} )

myDb = mySession.getSchema('test')

# Create a new collection 'my_collection'
myColl = myDb.createCollection('my_collection')

# Insert documents
myColl.add({'name': 'Sakila', 'age': 15}).execute()
myColl.add({'name': 'Susanne', 'age': 24}).execute()
myColl.add({'name': 'Mike', 'age': 39}).execute()

# Find a document
docs = myColl.find('name like :param1 AND age < :param2') \
          .limit(1) \
          .bind('param1','S%') \
          .bind('param2',20) \
          .execute()

# Print document
doc = docs.fetchOne()
print doc

# Drop the collection
session.dropCollection('test','my_collection')

Node.js JavaScript Code

// --------------------------------------------------
// Connecting to MySQL Server and working with a Collection

var mysqlx = require('mysqlx');

// Connect to server
mysqlx.getSession( {
  host: 'localhost', port: '33060',
  dbUser: 'mike', dbPassword: 's3cr3t!'
}).then(function(session) {
  return session.getSchema('test');
}).then(function(db) {
  // Create a new collection 'my_collection'
  return db.createCollection('my_collection');
}).then(function(myColl) {
  // Insert documents
  return Promise.all([
    myColl.add({name: 'Sakila', age: 15}).execute(),
    myColl.add({name: 'Susanne', age: 24}).execute(),
    myColl.add({name: 'Mike', age: 39}).execute()
  ]).then(function() {
    // Find a document
    return myColl.find('name like :name AND age < :age')
      .bind({ name: 'S*', age: 20 }).limit(1).execute();
  }).then(function(docs) {
    // Print document
    console.log(docs.fetchOne());

    // Drop the collection
    return myColl.drop();
  });
}).catch(function(err) {
  // Handle error
});

C# Code

{
// Connecting to MySQL Server and working with a Collection

// Connect to server
var mySession = MySQLX.GetSession("server=localhost;port=33060;user=mike;password=s3cr3t!;");

var myDb = mySession.GetSchema("test");

// Create a new collection "my_collection"
var myColl = myDb.CreateCollection("my_collection");

// Insert documents
myColl.Add(new { name = "Sakila", age = 15}).Execute();
myColl.Add(new { name = "Susanne", age = 24}).Execute();
myColl.Add(new { name = "Mike", age = 39}).Execute();

// Find a document
var docs = myColl.Find("name like :param1 AND age < :param2").Limit(1)
.Bind("param1", "S%").Bind("param2", 20).Execute();

// Print document
Console.WriteLine(docs.FetchOne());

// Drop the collection
myDb.DropCollection("my_collection");
}

Java Code

import com.mysql.cj.api.x.*;
import com.mysql.cj.x.MysqlxSessionFactory;

// Connect to server
String url = "mysqlx://localhost:33060/test?user=mike&password=s3cr3t!"
XSession mySession = new MysqlxSessionFactory().getSession(url);

Schema myDb = mySession.getSchema("test");

// Create a new collection 'my_collection'
Collection myColl = session.createCollection("my_collection");

// Insert documents
myColl.add("{\"name\":\"Sakila\", \"age\":15}").execute();
myColl.add("{\"name\":\"Susanne\", \"age\":24}").execute();
myColl.add("{\"name\":\"Mike\", \"age\":39}").execute();

// Find a document
DocResult docs = myColl.find("name like :name AND age < :age")
		.bind("name", 20).bind("age", 20).execute();

// Print document
DbDoc doc = docs.fetchOne();
System.out.println(doc);

// Drop the collection
myColl.drop();

C++ Code

		  // ___________________________________________________
		  // Connecting to MySQL Server and working with a Collection

		  #include <mysqlx.h>

		  // Connect to server
		  XSession session(33060, "mike", "s3cr3t!");
		  Schema db = session.getSchema("test");

		  // Create a new collection 'my_collection'
		  Collection myColl = db.createCollection("my_collection");

		  // Insert documents
		  myColl.add("{\"name\": \"Sakila\", \"age\": 15}").execute();
		  myColl.add("{\"name\": \"Susanne\", \"age\": 24}").execute();
		  myColl.add("{\"name\": \"Mike\", \"age\": 39}").execute();

		  // Find a document
		DocResult docs = myColl.find("name like :param1 AND age < :param2").limit(1)
		                       .bind("param1","S%").bind("param2",20).execute();

		  // Print document
		  cout << docs.fetchOne();

		  // Drop the collection
		  session.dropCollection("test", "my_collection");
	  

4.2 Collection Objects

Documents of the same type (for example users, products) are grouped together and stored in the database as collections. The X DevAPI uses Collection objects to store and retrieve documents.

4.2.1 Creating a Collection

In order to create a new collection call the createCollection() function from a Schema object. It returns a Collection object that can be used right away, for example to insert documents into the collection.

Optionally, the field reuseExistingObject can be set to true and passed as second parameter to prevent an error being generated if a collection with the same name already exists.

MySQL Shell JavaScript Code

// Create a new collection called 'my_collection'
var myColl = db.createCollection('my_collection');

MySQL Shell Python Code

# Create a new collection called 'my_collection'
myColl = db.createCollection('my_collection')

Node.js JavaScript Code

// Create a new collection called 'my_collection'
var promise = db.createCollection('my_collection');

// Create a new collection or reuse existing one
var promise = db.createCollection('my_collection', { ReuseExistingObject: true } );

C# Code

{
  // Create a new collection called "my_collection"
  var myColl = db.CreateCollection("my_collection");

  // Create a new collection or reuse existing one
  var myExistingColl = db.CreateCollection("my_collection", ReuseExistingObject: true);
}

Java Code

// Create a new collection called 'my_collection'
Collection myColl = db.createCollection("my_collection");

// Create a new collection or reuse existing one
// second parameter is: boolean reuseExistingObject
Collection myExistingColl = db.createCollection("my_collection", true);

C++ Code

// Create a new collection called 'my_collection'
Collection myColl = db.createCollection("my_collection");

// Create a new collection or reuse existing one
// second parameter is: boolean reuseExistingObject
Collection myExistingColl = db.createCollection("my_collection", true);

4.2.2 Working with Existing Collections

In order to retrieve a Collection object for an existing collection stored in the database call the getCollection() function from a Schema object.

MySQL Shell JavaScript Code

// Get a collection object for 'my_collection'
var myColl = db.getCollection('my_collection');

MySQL Shell Python Code

# Get a collection object for 'my_collection'
myColl = db.getCollection('my_collection')

Node.js JavaScript Code

// Get a collection object for 'my_collection'
var promise = db.getCollection('my_collection');

// Get a collection object but also ensure it exists in the database
var promise = db.getCollection('my_collection', { validateExistence: true } );

C# Code

{
  // Get a collection object for "my_collection"
  var myColl = db.GetCollection("my_collection");

  // Get a collection object but also ensure it exists in the database
  var myColl2 = db.GetCollection("my_collection", ValidateExistence: true);
}

Java Code

// Get a collection object for 'my_collection'
Collection myColl = db.getCollection("my_collection");

// Get a collection object but also ensure it exists in the database
// second parameter is: boolean requireExists
Collection myColl = db.getCollection("my_collection", true);

C++ Code

// Get a collection object for 'my_collection'
Collection myColl = db.getCollection("my_collection");

// Get a collection object but also ensure it exists in the database
// second parameter is: boolean requireExists
Collection myColl = db.getCollection("my_collection", true);

If the collection does not yet exist in the database any subsequent call of a Collection object function throws an error. To prevent this and catch the error right away set the validateExistence field to true and pass it as second parameter to db.getCollection().

The createCollection() together with the ReuseExistingObject field set to true can be used to create a new or reuse an existing collection with the given name.

Note

In most cases it is good practice to create database objects during development time and refrain from creating them on the fly during the production phase of a database project. Therefore it is best to separate the code that creates the collections in the database from the actual user application code.

4.3 Collection CRUD Function Overview

The following section explains the individual functions of the Collection object.

The most common operations to be performed on a Collection are the Create Read Update Delete (CRUD) statements. In order to speed up find operations it is recommended to make proper use of indexes.

Collection.add()

The Collection.add() function is used to store documents in the database. It takes a single document or a list of documents and is executed by the run() function.

The collection needs to be created with the Schema.createCollection() function before documents can be inserted. To insert documents into an existing collection use the Schema.getCollection() function.

The following example shows how to use the Collection.add() function. The example assumes that the test schema exists and that the collection my_collection does not exist.

MySQL Shell JavaScript Code

// Create a new collection
var myColl = db.createCollection('my_collection');

// Insert a document
myColl.add( { name: 'Sakila', age: 15 } ).execute();

// Insert several documents at once
myColl.add( [
{ name: 'Susanne', age: 24 },
{ name: 'Mike', age: 39 } ] ).execute();
	    

MySQL Shell Python Code

# Create a new collection
myColl = db.createCollection('my_collection')

# Insert a document
myColl.add( { 'name': 'Sakila', 'age': 15 } ).execute()

# Insert several documents at once
myColl.add( [
{ 'name': 'Susanne', 'age': 24 },
{ 'name': 'Mike', 'age': 39 } ] ).execute()
	    

Node.js JavaScript Code

// Create a new collection
db.createCollection('myCollection').then(function(myColl) {

  // Insert a document
  myColl.add( { name: 'Sakila', age: 15 } ).execute();

  // Insert several documents at once
  myColl.add( [
    { name: 'Susanne', age: 24 },
    { name: 'Mike', age: 39 }
  ] ).execute();
});
	    

C# Code

{
// Assumptions: test schema assigned to db, my_collection collection not exists

// Create a new collection
var myColl = db.CreateCollection("my_collection");

// Insert a document
myColl.Add(new { name = "Sakila", age = 15 }).Execute();

// Insert several documents at once
myColl.Add(new[] {
new { name = "Susanne", age = 24 },
new { name = "Mike", age = 39 } }).Execute();
}
	    

Java Code

// Create a new collection
Collection coll = db.createCollection("payments");

// Insert a document
coll.add("{\\"name\\":\\"Sakila\\", \\"age\\":15}");

// Insert several documents at once
List<String> jsonStrings = Arrays.asList("{\\"name\\":\\"Susanne\\", \\"age\\":24}",
"{\\"name\\":\\"Mike\\", \\"age\\":39}");
coll.add(jsonStrings);
	    

C++ Code

// Create a new collection
Collection coll = db.createCollection("payments");

// Insert a document
coll.add("{\"name\":\"Sakila\", \"age\":15}");

// Insert several documents at once
std::list<DbDoc> docs = {
  "{\"name\":\"Susanne\", \"age\":24}",
  "{\"name\":\"Mike\\", \"age\":39}"
};
coll.add(docs).execute();

The following diagram shows the full syntax definition.

Figure 4.1 Collection.add() Syntax Diagram

Collection.add() Syntax Diagram

Document Identity

Every document has a unique identifier called the document ID. The document ID is stored in the _id field of a document. The document ID is a string with a maximum length of 32 characters.

You do not need to provide the _id field manually. As shown, documents can be inserted without the field. If no _id field is given, a unique value is generated. Auto generated values are reported by the Result.getLastDocumentId() function. The example assumes that the test schema exists and is assigned to the variable db, that the collection my_collection exists and that custom_id is unique.

MySQL Shell JavaScript Code

// If the _id is provided, it will be honored
var result = myColl.add( { _id: 'custom_id', a : 1 } ).execute();
print("User Provided Id:", result.getLastDocumentId());

// If the _id is not provided, one will be automatically assigned
result = myColl.add( { b: 2 } ).execute();
print("Autogenerated Id:", result.getLastDocumentId());

MySQL Shell Python Code

# If the _id is provided, it will be honored
result = myColl.add( { '_id': 'custom_id', 'a' : 1 } ).execute()
print "User Provided Id: %s" % result.getLastDocumentId()

# If the _id is not provided, one will be automatically assigned
result = myColl.add( { 'b': 2 } ).execute()
print "Autogenerated Id: %s" % result.getLastDocumentId()
	    

Node.js JavaScript Code

// If the _id is provided, it will be honored
myColl.add( { _id: 'custom_id', a : 1 } ).execute().then(function (result) {
    console.log("User Provided Id:", result.getLastDocumentId());
});

// If the _id is not provided, one will be automatically assigned
myColl.add( { b: 2 } ).execute().then(function(result) {
    console.log("Autogenerated Id:", result.getLastDocumentId());
});

C# Code

{
// If the _id is provided, it will be honored
var result = myColl.Add(new { _id = "custom_id", a = 1 }).Execute();
Console.WriteLine("User Provided Id:", result.AutoIncrementValue);

// If the _id is not provided, one will be automatically assigned
result = myColl.Add(new { b = 2 }).Execute();
Console.WriteLine("Autogenerated Id:", result.AutoIncrementValue);
}

Java Code

// If the _id is provided, it will be honored
Result result = myColl.add("{\\"_id\\":\\"custom_id\\",\\"a\\":1}").execute();
print("User Provided Id:", result.getLastDocumentIds().get(0));

// If the _id is not provided, one will be automatically assigned
result = myColl.add("{\\"b\\":2}").execute();
print("Autogenerated Id:", result.getLastDocumentIds().get(0));

C++ Code

// If the _id is provided, it will be honored
DocResult result = myColl.add("{ \"_id\": \"custom_id\", \"a\" : 1 }").execute();
cout << "User Provided Id:" << result.getLastDocumentId() << endl;

// If the _id is not provided, one will be automatically assigned
result = myColl.add("{ \"b\": 2 }").execute();
cout << "Autogenerated Id:" << result.getLastDocumentId()) << endl;

Some documents have a natural unique key. For example, a collection that holds a list of books is likely to include the International Standard Book Number (ISBN) for each document that represents a book. The ISBN is a string with a length of 13 characters which is well within the length limit of the _id field.

MySQL Shell JavaScript Code

// using a book's unique ISBN as the document ID
myColl.add( {
_id: "978-1449374020",
title: "MySQL Cookbook: Solutions for Database Developers and Administrators"
}).execute();

Use find() to fetch the newly inserted book from the collection by its document ID:

MySQL Shell JavaScript Code

var book = myColl.find('_id = "978-1449374020"').execute();

Currently, the X DevAPI does not support using any document field other than the implicit _id as the document ID. There is no way of defining a different document ID (primary key).

Collection.find()

The find() function is used to get documents from the database. It takes a SearchConditionStr as a parameter to specify the documents that should be returned from the database. Several methods such as fields(), sort(), skip() and limit() can be chained to the find() function to further refine the result.

The fetch() function actually triggers the execution of the operation. The example assumes that the test schema exists and that the collection my_collection exists.

MySQL Shell JavaScript Code

// Use the collection 'my_collection'
var myColl = db.getCollection('my_collection');

// Find a single document that has a field 'name' starts with an 'S'
var docs = myColl.find('name like :param').
           limit(1).bind('param', 'S%').execute();

print(docs.fetchOne());

// Get all documents with a field 'name' that starts with an 'S'
docs = myColl.find('name like :param').
        bind('param','S%').execute();

var myDoc;
while (myDoc = docs.fetchOne()) {
print(myDoc);
}

MySQL Shell Python Code

# Use the collection 'my_collection'
myColl = db.getCollection('my_collection')

# Find a single document that has a field 'name' starts with an 'S'
docs = myColl.find('name like :param').limit(1).bind('param', 'S%').execute()

print docs.fetchOne()

# Get all documents with a field 'name' that starts with an 'S'
docs = myColl.find('name like :param').bind('param','S%').execute()

myDoc = docs.fetchOne()
while myDoc:
print myDoc
myDoc = docs.fetchOne()

Node.js JavaScript Code

// Use the collection 'my_collection'
var myColl = db.getCollection('my_collection');

// Find a single document that has a field 'name' starts with an 'S'
myColl.find('name like :name').bind('S%').limit(1).execute(function (doc) {
  console.log(doc);
});

// Get all documents with a field 'name' that starts with an 'S'
myColl.find('name like :name')
.bind('S%').execute(function (myDoc) {
  console.log(myDoc);
});

C# Code

{
// Use the collection "my_collection"
var myColl = db.GetCollection("my_collection");

// Find a single document that has a field "name" starts with an "S"
var docs = myColl.Find("name like :param")
.Limit(1).Bind("param", "S%").Execute();

Console.WriteLine(docs.FetchOne());

// Get all documents with a field "name" that starts with an "S"
docs = myColl.Find("name like :param")
.Bind("param", "S%").Execute();

while (docs.Next())
{
Console.WriteLine(docs.Current);
}
}

Java Code

// Use the collection 'my_collection'
Collection myColl = db.useCollection("my_collection");

// Find a single document that has a field 'name' starts with an 'S'
DocResult docs = myColl.find("name like :name")
.bind("name", "S%").execute();

System.out.println(docs.fetchOne());

// Get all documents with a field 'name' that starts with an 'S'
docs = myColl.find("name like :name")
.bind("name", "S%").execute();

while (docs.hasNext()) {
DbDoc myDoc = docs.next();
System.out.println(myDoc);
}

C++ Code

// Use the collection 'my_collection'
Collection myColl = db.getCollection("my_collection");

// Find a single document that has a field 'name' starts with an 'S'
DocResult docs = myColl.find("name like :param")
                       .limit(1).bind("param", "S%").execute();

cout << docs.fetchOne() << endl;

// Get all documents with a field 'name' that starts with an 'S'
docs = myColl.find("name like :param")
             .bind("param","S%").execute();

DbDoc myDoc;
while ((myDoc = docs.fetchOne()))
{
  cout << docs.fetchOne() << endl;
}

The following diagram shows the full syntax definition.

Figure 4.2 Collection.find() Syntax Diagram

Collection.find() Syntax Diagram

For more information, see Section 11.7, “Other EBNF Definitions”.

Collection.modify()

Figure 4.3 Collection.modify() Syntax Diagram

Collection.modify() Syntax Diagram

Collection.remove()

Figure 4.4 Collection.remove() Syntax Diagram

Collection.remove() Syntax Diagram