diff --git a/test/examples/array_filters.js b/test/examples/array_filters.js new file mode 100644 index 00000000000..79f320352e9 --- /dev/null +++ b/test/examples/array_filters.js @@ -0,0 +1,36 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(project-fields-from-query):', function() { + let client; + let collection; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + collection = client.db(this.configuration.db).collection('arrayFilterUpdateExample'); + }); + + afterEach(async function() { + await client.close(); + client = undefined; + collection = undefined; + }); + + it('supports array filters when updating', { + metadata: { requires: { mongodb: '>=3.6.x', topology: ['single'] } }, + test: async function() { + // 3. Exploiting the power of arrays + await collection.updateOne( + { _id: 1 }, + { $set: { 'a.$[i].b': 2 } }, + { arrayFilters: [{ 'i.b': 0 }] } + ); + } + }); +}); diff --git a/test/examples/causal_consistency.js b/test/examples/causal_consistency.js new file mode 100644 index 00000000000..494ddce890c --- /dev/null +++ b/test/examples/causal_consistency.js @@ -0,0 +1,49 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(causal-consistency):', function() { + let client; + let collection; + let session; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + collection = client.db(this.configuration.db).collection('arrayFilterUpdateExample'); + }); + + afterEach(async function() { + if (session) { + await session.endSession(); + session = undefined; + } + + await client.close(); + client = undefined; + collection = undefined; + }); + + it('supports causal consistency', { + metadata: { + requires: { topology: ['single'], mongodb: '>=3.6.0' }, + sessions: { skipLeakTests: true } + }, + + test: async function() { + const session = client.startSession({ causalConsistency: true }); + + collection.insertOne({ darmok: 'jalad' }, { session }); + collection.updateOne({ darmok: 'jalad' }, { $set: { darmok: 'tanagra' } }, { session }); + + const results = await collection.find({}, { session }).toArray(); + + expect(results).to.exist; + } + }); +}); diff --git a/test/examples/insert.js b/test/examples/insert.js new file mode 100644 index 00000000000..293284a14f6 --- /dev/null +++ b/test/examples/insert.js @@ -0,0 +1,77 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(insert):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Insert a Single Document', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 1 + await db.collection('inventory').insertOne({ + item: 'canvas', + qty: 100, + tags: ['cotton'], + size: { h: 28, w: 35.5, uom: 'cm' } + }); + // End Example 1 + + // Start Example 2 + const cursor = db.collection('inventory').find({ item: 'canvas' }); + // End Example 2 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Insert Multiple Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 3 + await db.collection('inventory').insertMany([ + { + item: 'journal', + qty: 25, + tags: ['blank', 'red'], + size: { h: 14, w: 21, uom: 'cm' } + }, + { + item: 'mat', + qty: 85, + tags: ['gray'], + size: { h: 27.9, w: 35.5, uom: 'cm' } + }, + { + item: 'mousepad', + qty: 25, + tags: ['gel', 'blue'], + size: { h: 19, w: 22.85, uom: 'cm' } + } + ]); + // End Example 3 + + expect(await db.collection('inventory').count({})).to.equal(3); + } + }); +}); diff --git a/test/examples/project_fields_from_query_results.js b/test/examples/project_fields_from_query_results.js new file mode 100644 index 00000000000..ae4781530f9 --- /dev/null +++ b/test/examples/project_fields_from_query_results.js @@ -0,0 +1,222 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(project-fields-from-query):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 42 + await db.collection('inventory').insertMany([ + { + item: 'journal', + status: 'A', + size: { h: 14, w: 21, uom: 'cm' }, + instock: [{ warehouse: 'A', qty: 5 }] + }, + { + item: 'notebook', + status: 'A', + size: { h: 8.5, w: 11, uom: 'in' }, + instock: [{ warehouse: 'C', qty: 5 }] + }, + { + item: 'paper', + status: 'D', + size: { h: 8.5, w: 11, uom: 'in' }, + instock: [{ warehouse: 'A', qty: 60 }] + }, + { + item: 'planner', + status: 'D', + size: { h: 22.85, w: 30, uom: 'cm' }, + instock: [{ warehouse: 'A', qty: 40 }] + }, + { + item: 'postcard', + status: 'A', + size: { h: 10, w: 15.25, uom: 'cm' }, + instock: [{ warehouse: 'B', qty: 15 }, { warehouse: 'C', qty: 35 }] + } + ]); + // End Example 42 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Return All Fields in Matching Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 43 + const cursor = db.collection('inventory').find({ + status: 'A' + }); + // End Example 43 + + expect(await cursor.count()).to.equal(3); + } + }); + + it('Return the Specified Fields and the ``_id`` Field Only', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 44 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ item: 1, status: 1 }); + // End Example 44 + + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'status']); + expect(doc).to.not.have.all.keys(['size', 'instock']); + }); + } + }); + + it('Suppress ``_id`` Field', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 45 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ item: 1, status: 1, _id: 0 }); + // End Example 45 + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['item', 'status']); + expect(doc).to.not.have.all.keys(['_id', 'size', 'instock']); + }); + } + }); + + it('Return All But the Excluded Fields', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 46 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ status: 0, instock: 0 }); + // End Example 46 + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'size']); + expect(doc).to.not.have.all.keys(['status', 'instock']); + }); + } + }); + + it('Return Specific Fields in Embedded Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 47 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ item: 1, status: 1, 'size.uom': 1 }); + // End Example 47 + const docs = await cursor.toArray(); + + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'status', 'size']); + expect(doc).to.not.have.property('instock'); + + const size = doc.size; + expect(size).to.have.property('uom'); + expect(size).to.not.have.all.keys(['h', 'w']); + }); + } + }); + + it('Suppress Specific Fields in Embedded Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 48 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ 'size.uom': 0 }); + // End Example 48 + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'status', 'size', 'instock']); + const size = doc.size; + expect(size).to.have.all.keys(['h', 'w']); + expect(size).to.not.have.property('uom'); + }); + } + }); + + it('Projection on Embedded Documents in an Array', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 49 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ item: 1, status: 1, 'instock.qty': 1 }); + // End Example 49 + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'status', 'instock']); + expect(doc).to.not.have.property('size'); + doc.instock.forEach(function(subdoc) { + expect(subdoc).to.have.property('qty'); + expect(subdoc).to.not.have.property('warehouse'); + }); + }); + } + }); + + it('Project Specific Array Elements in the Returned Array', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 50 + const cursor = db + .collection('inventory') + .find({ + status: 'A' + }) + .project({ item: 1, status: 1, instock: { $slice: -1 } }); + // End Example 50 + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc).to.have.all.keys(['_id', 'item', 'status', 'instock']); + expect(doc).to.not.have.property('size'); + expect(doc) + .to.have.property('instock') + .with.a.lengthOf(1); + }); + } + }); +}); diff --git a/test/examples/query.js b/test/examples/query.js new file mode 100644 index 00000000000..f2dcff53ba2 --- /dev/null +++ b/test/examples/query.js @@ -0,0 +1,133 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(query):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 6 + await db.collection('inventory').insertMany([ + { + item: 'journal', + qty: 25, + size: { h: 14, w: 21, uom: 'cm' }, + status: 'A' + }, + { + item: 'notebook', + qty: 50, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'A' + }, + { + item: 'paper', + qty: 100, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'D' + }, + { + item: 'planner', + qty: 75, + size: { h: 22.85, w: 30, uom: 'cm' }, + status: 'D' + }, + { + item: 'postcard', + qty: 45, + size: { h: 10, w: 15.25, uom: 'cm' }, + status: 'A' + } + ]); + // End Example 6 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('select all documents in a collection', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 7 + const cursor = db.collection('inventory').find({}); + // End Example 7 + + expect(await cursor.count()).to.equal(5); + } + }); + + it('Specify Equality Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 9 + const cursor = db.collection('inventory').find({ status: 'D' }); + // End Example 9 + + expect(await cursor.count()).to.equal(2); + } + }); + + it('Specify Conditions Using Query Operators', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 10 + const cursor = db.collection('inventory').find({ + status: { $in: ['A', 'D'] } + }); + // End Example 10 + expect(await cursor.count()).to.equal(5); + } + }); + + it('Specify ``AND`` Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 11 + const cursor = db.collection('inventory').find({ + status: 'A', + qty: { $lt: 30 } + }); + // End Example 11 + expect(await cursor.count()).to.equal(1); + } + }); + + it('Specify ``OR`` Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 12 + const cursor = db.collection('inventory').find({ + $or: [{ status: 'A' }, { qty: { $lt: 30 } }] + }); + // End Example 12 + expect(await cursor.count()).to.equal(3); + } + }); + + it('Specify ``AND`` as well as ``OR`` Conditions', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 13 + const cursor = db.collection('inventory').find({ + status: 'A', + $or: [{ qty: { $lt: 30 } }, { item: { $regex: '^p' } }] + }); + // End Example 13 + expect(await cursor.count()).to.equal(2); + } + }); +}); diff --git a/test/examples/query_array_of_documents.js b/test/examples/query_array_of_documents.js new file mode 100644 index 00000000000..8e703d5678b --- /dev/null +++ b/test/examples/query_array_of_documents.js @@ -0,0 +1,156 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(query-array-of-documents):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 29 + await db.collection('inventory').insertMany([ + { + item: 'journal', + instock: [{ warehouse: 'A', qty: 5 }, { warehouse: 'C', qty: 15 }] + }, + { + item: 'notebook', + instock: [{ warehouse: 'C', qty: 5 }] + }, + { + item: 'paper', + instock: [{ warehouse: 'A', qty: 60 }, { warehouse: 'B', qty: 15 }] + }, + { + item: 'planner', + instock: [{ warehouse: 'A', qty: 40 }, { warehouse: 'B', qty: 5 }] + }, + { + item: 'postcard', + instock: [{ warehouse: 'B', qty: 15 }, { warehouse: 'C', qty: 35 }] + } + ]); + // End Example 29 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Query for a Document Nested in an Array', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 30 + const cursor = db.collection('inventory').find({ + instock: { warehouse: 'A', qty: 5 } + }); + // End Example 30 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Query for a Document Nested in an Array - document order', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 31 + const cursor = db.collection('inventory').find({ + instock: { qty: 5, warehouse: 'A' } + }); + // End Example 31 + + expect(await cursor.count()).to.equal(0); + } + }); + + it('Use the Array Index to Query for a Field in the Embedded Document', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 32 + const cursor = db.collection('inventory').find({ + 'instock.0.qty': { $lte: 20 } + }); + // End Example 32 + + expect(await cursor.count()).to.equal(3); + } + }); + + it('Specify a Query Condition on a Field Embedded in an Array of Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 33 + const cursor = db.collection('inventory').find({ + 'instock.qty': { $lte: 20 } + }); + // End Example 33 + + expect(await cursor.count()).to.equal(5); + } + }); + + it('A Single Nested Document Meets Multiple Query Conditions on Nested Fields', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 34 + const cursor = db.collection('inventory').find({ + instock: { $elemMatch: { qty: 5, warehouse: 'A' } } + }); + // End Example 34 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('A Single Nested Document Meets Multiple Query Conditions on Nested Fields: operators', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 35 + const cursor = db.collection('inventory').find({ + instock: { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } + }); + // End Example 35 + + expect(await cursor.count()).to.equal(3); + } + }); + + it('Combination of Elements Satisfies the Criteria', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 36 + const cursor = db.collection('inventory').find({ + 'instock.qty': { $gt: 10, $lte: 20 } + }); + // End Example 36 + + expect(await cursor.count()).to.equal(4); + } + }); + + it('Combination of Elements Satisfies the Criteria 2', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 37 + const cursor = db.collection('inventory').find({ + 'instock.qty': 5, + 'instock.warehouse': 'A' + }); + // End Example 37 + + expect(await cursor.count()).to.equal(2); + } + }); +}); diff --git a/test/examples/query_arrays.js b/test/examples/query_arrays.js new file mode 100644 index 00000000000..683ef43605f --- /dev/null +++ b/test/examples/query_arrays.js @@ -0,0 +1,165 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(query-arrays):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 20 + await db.collection('inventory').insertMany([ + { + item: 'journal', + qty: 25, + tags: ['blank', 'red'], + dim_cm: [14, 21] + }, + { + item: 'notebook', + qty: 50, + tags: ['red', 'blank'], + dim_cm: [14, 21] + }, + { + item: 'paper', + qty: 100, + tags: ['red', 'blank', 'plain'], + dim_cm: [14, 21] + }, + { + item: 'planner', + qty: 75, + tags: ['blank', 'red'], + dim_cm: [22.85, 30] + }, + { + item: 'postcard', + qty: 45, + tags: ['blue'], + dim_cm: [10, 15.25] + } + ]); + // End Example 20 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Match an Array', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 21 + const cursor = db.collection('inventory').find({ + tags: ['red', 'blank'] + }); + // End Example 21 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Match an Array: $all', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 22 + const cursor = db.collection('inventory').find({ + tags: { $all: ['red', 'blank'] } + }); + // End Example 22 + + expect(await cursor.count()).to.equal(4); + } + }); + + it('Query an Array for an Element', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 23 + const cursor = db.collection('inventory').find({ + tags: 'red' + }); + // End Example 23 + + expect(await cursor.count()).to.equal(4); + } + }); + + it('Query an Array for an Element w/ operators', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 24 + const cursor = db.collection('inventory').find({ + dim_cm: { $gt: 25 } + }); + // End Example 24 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Query an Array with Compound Filter Conditions on the Array Elements', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 25 + const cursor = db.collection('inventory').find({ + dim_cm: { $gt: 15, $lt: 20 } + }); + // End Example 25 + + expect(await cursor.count()).to.equal(4); + } + }); + + it('Query for an Array Element that Meets Multiple Criteria', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 26 + const cursor = db.collection('inventory').find({ + dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } + }); + // End Example 26 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Query for an Element by the Array Index Position', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 27 + const cursor = db.collection('inventory').find({ + 'dim_cm.1': { $gt: 25 } + }); + // End Example 27 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Query an Array by Array Length', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 28 + const cursor = db.collection('inventory').find({ + tags: { $size: 3 } + }); + // End Example 28 + + expect(await cursor.count()).to.equal(1); + } + }); +}); diff --git a/test/examples/query_embedded_documents.js b/test/examples/query_embedded_documents.js new file mode 100644 index 00000000000..512565306fd --- /dev/null +++ b/test/examples/query_embedded_documents.js @@ -0,0 +1,128 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(query-embedded-documents):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 14 + await db.collection('inventory').insertMany([ + { + item: 'journal', + qty: 25, + size: { h: 14, w: 21, uom: 'cm' }, + status: 'A' + }, + { + item: 'notebook', + qty: 50, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'A' + }, + { + item: 'paper', + qty: 100, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'D' + }, + { + item: 'planner', + qty: 75, + size: { h: 22.85, w: 30, uom: 'cm' }, + status: 'D' + }, + { + item: 'postcard', + qty: 45, + size: { h: 10, w: 15.25, uom: 'cm' }, + status: 'A' + } + ]); + // End Example 14 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Match an Embedded/Nested Document', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 15 + const cursor = db.collection('inventory').find({ + size: { h: 14, w: 21, uom: 'cm' } + }); + // End Example 15 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Match an Embedded/Nested Document - document order', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 16 + const cursor = db.collection('inventory').find({ + size: { w: 21, h: 14, uom: 'cm' } + }); + // End Example 16 + + expect(await cursor.count()).to.equal(0); + } + }); + + it('Specify Equality Match on a Nested Field', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 17 + const cursor = db.collection('inventory').find({ + 'size.uom': 'in' + }); + // End Example 17 + + expect(await cursor.count()).to.equal(2); + } + }); + + it('Specify Match using Query Operator', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 18 + const cursor = db.collection('inventory').find({ + 'size.h': { $lt: 15 } + }); + // End Example 18 + + expect(await cursor.count()).to.equal(4); + } + }); + + it('Specify ``AND`` Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 19 + const cursor = db.collection('inventory').find({ + 'size.h': { $lt: 15 }, + 'size.uom': 'in', + status: 'D' + }); + // End Example 19 + + expect(await cursor.count()).to.equal(1); + } + }); +}); diff --git a/test/examples/query_for_null_fields.js b/test/examples/query_for_null_fields.js new file mode 100644 index 00000000000..e0efb54c932 --- /dev/null +++ b/test/examples/query_for_null_fields.js @@ -0,0 +1,69 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(query-for-null-fields):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 38 + await db.collection('inventory').insertMany([{ _id: 1, item: null }, { _id: 2 }]); + // End Example 38 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Equality Filter', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 39 + const cursor = db.collection('inventory').find({ + item: null + }); + // End Example 39 + + expect(await cursor.count()).to.equal(2); + } + }); + + it('Type Check', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 40 + const cursor = db.collection('inventory').find({ + item: { $type: 10 } + }); + // End Example 40 + + expect(await cursor.count()).to.equal(1); + } + }); + + it('Existence Check', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 41 + const cursor = db.collection('inventory').find({ + item: { $exists: false } + }); + // End Example 41 + + expect(await cursor.count()).to.equal(1); + } + }); +}); diff --git a/test/examples/remove_documents.js b/test/examples/remove_documents.js new file mode 100644 index 00000000000..875b3e6e42d --- /dev/null +++ b/test/examples/remove_documents.js @@ -0,0 +1,94 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(remove-documents):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 55 + await db.collection('inventory').insertMany([ + { + item: 'journal', + qty: 25, + size: { h: 14, w: 21, uom: 'cm' }, + status: 'A' + }, + { + item: 'notebook', + qty: 50, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'P' + }, + { + item: 'paper', + qty: 100, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'D' + }, + { + item: 'planner', + qty: 75, + size: { h: 22.85, w: 30, uom: 'cm' }, + status: 'D' + }, + { + item: 'postcard', + qty: 45, + size: { h: 10, w: 15.25, uom: 'cm' }, + status: 'A' + } + ]); + // End Example 55 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Delete All Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 56 + await db.collection('inventory').deleteMany({}); + // End Example 56 + const cursor = db.collection('inventory').find({}); + expect(await cursor.count()).to.equal(0); + } + }); + + it('Delete All Documents that Match a Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 57 + await db.collection('inventory').deleteMany({ status: 'A' }); + // End Example 57 + const cursor = db.collection('inventory').find({}); + expect(await cursor.count()).to.equal(3); + } + }); + + it('Delete Only One Document that Matches a Condition', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 58 + await db.collection('inventory').deleteOne({ status: 'D' }); + // End Example 58 + const cursor = db.collection('inventory').find({}); + expect(await cursor.count()).to.equal(4); + } + }); +}); diff --git a/test/examples/transactions.js b/test/examples/transactions.js new file mode 100644 index 00000000000..f65508c3ef0 --- /dev/null +++ b/test/examples/transactions.js @@ -0,0 +1,222 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(transactions):', function() { + let client; + let log; + + before(async function() { + await setupDatabase(this.configuration); + log = console.log; + console.log = () => {}; + }); + + after(function() { + console.log = log; + log = undefined; + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + await client.db('hr').dropDatabase(); + await client.db('hr').createCollection('employees'); + await client.db('reporting').dropDatabase(); + await client.db('reporting').createCollection('events'); + }); + + afterEach(async function() { + await client.close(); + client = undefined; + }); + + it('Transactions Retry Example 1', { + metadata: { requires: { topology: ['replicaset'], mongodb: '>=3.8.0' } }, + test: async function() { + // Start Transactions Retry Example 1 + async function runTransactionWithRetry(txnFunc, client, session) { + try { + await txnFunc(client, session); + } catch (error) { + console.log('Transaction aborted. Caught exception during transaction.'); + + // If transient error, retry the whole transaction + if (error.errorLabels && error.errorLabels.indexOf('TransientTransactionError') < 0) { + console.log('TransientTransactionError, retrying transaction ...'); + await runTransactionWithRetry(txnFunc, client, session); + } else { + throw error; + } + } + } + // End Transactions Retry Example 1 + + async function updateEmployeeInfo(client, session) { + session.startTransaction({ + readConcern: { level: 'snapshot' }, + writeConcern: { w: 'majority' } + }); + + const employeesCollection = client.db('hr').collection('employees'); + const eventsCollection = client.db('reporting').collection('events'); + + await employeesCollection.updateOne( + { employee: 3 }, + { $set: { status: 'Inactive' } }, + { session } + ); + await eventsCollection.insertOne( + { + employee: 3, + status: { new: 'Inactive', old: 'Active' } + }, + { session } + ); + + try { + await session.commitTransaction(); + } catch (error) { + await session.abortTransaction(); + throw error; + } + } + + return client.withSession(session => + runTransactionWithRetry(updateEmployeeInfo, client, session) + ); + } + }); + + it('Transactions Retry Example 2', { + metadata: { requires: { topology: ['replicaset'], mongodb: '>=3.8.0' } }, + test: async function() { + // Start Transactions Retry Example 2 + async function commitWithRetry(session) { + try { + await session.commitTransaction(); + console.log('Transaction committed.'); + } catch (error) { + if ( + error.errorLabels && + error.errorLabels.indexOf('UnknownTransactionCommitResult') < 0 + ) { + console.log('UnknownTransactionCommitResult, retrying commit operation ...'); + await commitWithRetry(session); + } else { + console.log('Error during commit ...'); + throw error; + } + } + } + // End Transactions Retry Example 2 + + async function updateEmployeeInfo(client, session) { + session.startTransaction({ + readConcern: { level: 'snapshot' }, + writeConcern: { w: 'majority' } + }); + + const employeesCollection = client.db('hr').collection('employees'); + const eventsCollection = client.db('reporting').collection('events'); + + await employeesCollection.updateOne( + { employee: 3 }, + { $set: { status: 'Inactive' } }, + { session } + ); + await eventsCollection.insertOne( + { + employee: 3, + status: { new: 'Inactive', old: 'Active' } + }, + { session } + ); + + try { + await commitWithRetry(session); + } catch (error) { + await session.abortTransaction(); + throw error; + } + } + + return client.withSession(session => updateEmployeeInfo(client, session)); + } + }); + + it('Transaction Retry Example 3', { + metadata: { requires: { topology: ['replicaset'], mongodb: '>=3.8.0' } }, + test: async function() { + // Start Transactions Retry Example 3 + async function commitWithRetry(session) { + try { + await session.commitTransaction(); + console.log('Transaction committed.'); + } catch (error) { + if ( + error.errorLabels && + error.errorLabels.indexOf('UnknownTransactionCommitResult') < 0 + ) { + console.log('UnknownTransactionCommitResult, retrying commit operation ...'); + await commitWithRetry(session); + } else { + console.log('Error during commit ...'); + throw error; + } + } + } + + async function runTransactionWithRetry(txnFunc, client, session) { + try { + await txnFunc(client, session); + } catch (error) { + console.log('Transaction aborted. Caught exception during transaction.'); + + // If transient error, retry the whole transaction + if (error.errorLabels && error.errorLabels.indexOf('TransientTransactionError') < 0) { + console.log('TransientTransactionError, retrying transaction ...'); + await runTransactionWithRetry(txnFunc, client, session); + } else { + throw error; + } + } + } + + async function updateEmployeeInfo(client, session) { + session.startTransaction({ + readConcern: { level: 'snapshot' }, + writeConcern: { w: 'majority' } + }); + + const employeesCollection = client.db('hr').collection('employees'); + const eventsCollection = client.db('reporting').collection('events'); + + await employeesCollection.updateOne( + { employee: 3 }, + { $set: { status: 'Inactive' } }, + { session } + ); + await eventsCollection.insertOne( + { + employee: 3, + status: { new: 'Inactive', old: 'Active' } + }, + { session } + ); + + try { + await commitWithRetry(session); + } catch (error) { + await session.abortTransaction(); + throw error; + } + } + + return client.withSession(session => + runTransactionWithRetry(updateEmployeeInfo, client, session) + ); + // End Transactions Retry Example 3 + } + }); +}); diff --git a/test/examples/update_documents.js b/test/examples/update_documents.js new file mode 100644 index 00000000000..a5b7779a46c --- /dev/null +++ b/test/examples/update_documents.js @@ -0,0 +1,187 @@ +'use strict'; + +const setupDatabase = require('../functional/shared').setupDatabase; +const expect = require('chai').expect; +const MongoClient = require('../../lib/mongo_client'); + +describe('examples(update-documents):', function() { + let client; + let db; + + before(async function() { + await setupDatabase(this.configuration); + }); + + beforeEach(async function() { + client = await MongoClient.connect(this.configuration.url()); + db = client.db(this.configuration.db); + + await db.collection('inventory').deleteMany({}); + // Start Example 51 + await db.collection('inventory').insertMany([ + { + item: 'canvas', + qty: 100, + size: { h: 28, w: 35.5, uom: 'cm' }, + status: 'A' + }, + { + item: 'journal', + qty: 25, + size: { h: 14, w: 21, uom: 'cm' }, + status: 'A' + }, + { + item: 'mat', + qty: 85, + size: { h: 27.9, w: 35.5, uom: 'cm' }, + status: 'A' + }, + { + item: 'mousepad', + qty: 25, + size: { h: 19, w: 22.85, uom: 'cm' }, + status: 'P' + }, + { + item: 'notebook', + qty: 50, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'P' + }, + { + item: 'paper', + qty: 100, + size: { h: 8.5, w: 11, uom: 'in' }, + status: 'D' + }, + { + item: 'planner', + qty: 75, + size: { h: 22.85, w: 30, uom: 'cm' }, + status: 'D' + }, + { + item: 'postcard', + qty: 45, + size: { h: 10, w: 15.25, uom: 'cm' }, + status: 'A' + }, + { + item: 'sketchbook', + qty: 80, + size: { h: 14, w: 21, uom: 'cm' }, + status: 'A' + }, + { + item: 'sketch pad', + qty: 95, + size: { h: 22.85, w: 30.5, uom: 'cm' }, + status: 'A' + } + ]); + // End Example 51 + }); + + afterEach(async function() { + await client.close(); + client = undefined; + db = undefined; + }); + + it('Update a Single Document', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 52 + await db.collection('inventory').updateOne( + { item: 'paper' }, + { + $set: { 'size.uom': 'cm', status: 'P' }, + $currentDate: { lastModified: true } + } + ); + // End Example 52 + const cursor = db.collection('inventory').find({ + item: 'paper' + }); + + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc) + .to.have.nested.property('size.uom') + .that.equals('cm'); + expect(doc) + .to.have.property('status') + .that.equals('P'); + expect(doc).to.have.property('lastModified'); + }); + } + }); + + it('Update Multiple Documents', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 53 + await db.collection('inventory').updateMany( + { qty: { $lt: 50 } }, + { + $set: { 'size.uom': 'in', status: 'P' }, + $currentDate: { lastModified: true } + } + ); + // End Example 53 + + const cursor = db.collection('inventory').find({ + qty: { $lt: 50 } + }); + + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(doc) + .to.have.nested.property('size.uom') + .that.equals('in'); + expect(doc) + .to.have.property('status') + .that.equals('P'); + expect(doc).to.have.property('lastModified'); + }); + } + }); + + it('Replace a Document', { + metadata: { requires: { topology: ['single'], mongodb: '>= 2.8.0' } }, + test: async function() { + // Start Example 54 + await db.collection('inventory').replaceOne( + { item: 'paper' }, + { + $set: { + item: 'paper', + instock: [{ warehouse: 'A', qty: 60 }, { warehouse: 'B', qty: 40 }] + }, + $unset: { + qty: '', + size: '', + status: '', + lastModified: '' + } + } + ); + // End Example 54 + + const cursor = db + .collection('inventory') + .find({ item: 'paper' }) + .project({ _id: 0 }); + + const docs = await cursor.toArray(); + docs.forEach(function(doc) { + expect(Object.keys(doc)).to.have.a.lengthOf(2); + expect(doc).to.have.property('item'); + expect(doc) + .to.have.property('instock') + .that.has.a.lengthOf(2); + }); + } + }); +}); diff --git a/test/functional/examples_tests.js b/test/functional/examples_tests.js deleted file mode 100644 index 1577affbb49..00000000000 --- a/test/functional/examples_tests.js +++ /dev/null @@ -1,1270 +0,0 @@ -'use strict'; - -var assert = require('assert'); -const expect = require('chai').expect; -var co = require('co'); -var test = require('./shared').assert; -var setupDatabase = require('./shared').setupDatabase; - -function processResult() {} - -describe('Examples', function() { - before(function() { - return setupDatabase(this.configuration); - }); - - /** - * @ignore - */ - it('first three examples', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise1 = - // Start Example 1 - db - .collection('inventory') - .insertOne({ - item: 'canvas', - qty: 100, - tags: ['cotton'], - size: { h: 28, w: 35.5, uom: 'cm' } - }) - .then(function(result) { - processResult(result); - }) - // End Example 1 - .then(() => { - return db.collection('inventory').count({}); - }); - - assert.equal(1, yield promise1); - - // Start Example 2 - var cursor = db.collection('inventory').find({ - item: 'canvas' - }); - // End Example 2 - - assert.equal(1, yield cursor.count()); - - var promise3 = - // Start Example 3 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - qty: 25, - tags: ['blank', 'red'], - size: { h: 14, w: 21, uom: 'cm' } - }, - { - item: 'mat', - qty: 85, - tags: ['gray'], - size: { h: 27.9, w: 35.5, uom: 'cm' } - }, - { - item: 'mousepad', - qty: 25, - tags: ['gel', 'blue'], - size: { h: 19, w: 22.85, uom: 'cm' } - } - ]) - .then(function(result) { - processResult(result); - }) - // End Example 3 - .then(() => { - return db.collection('inventory').count({}); - }); - - assert.equal(4, yield promise3); - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('query top level fields', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 6 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - qty: 25, - size: { h: 14, w: 21, uom: 'cm' }, - status: 'A' - }, - { - item: 'notebook', - qty: 50, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'A' - }, - { - item: 'paper', - qty: 100, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'D' - }, - { - item: 'planner', - qty: 75, - size: { h: 22.85, w: 30, uom: 'cm' }, - status: 'D' - }, - { - item: 'postcard', - qty: 45, - size: { h: 10, w: 15.25, uom: 'cm' }, - status: 'A' - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 6 - yield promise; - - assert.equal(5, yield db.collection('inventory').count()); - - /* eslint-disable */ - - // Start Example 7 - var cursor = db.collection('inventory').find({}); - // End Example 7 - assert.equal(5, yield cursor.count()); - - // Start Example 9 - var cursor = db.collection('inventory').find({ status: 'D' }); - // End Example 9 - assert.equal(2, yield cursor.count()); - - // Start Example 10 - var cursor = db.collection('inventory').find({ - status: { $in: ['A', 'D'] } - }); - // End Example 10 - assert.equal(5, yield cursor.count()); - - // Start Example 11 - var cursor = db.collection('inventory').find({ - status: 'A', - qty: { $lt: 30 } - }); - // End Example 11 - assert.equal(1, yield cursor.count()); - - // Start Example 12 - var cursor = db.collection('inventory').find({ - $or: [{ status: 'A' }, { qty: { $lt: 30 } }] - }); - // End Example 12 - assert.equal(3, yield cursor.count()); - - // Start Example 13 - var cursor = db.collection('inventory').find({ - status: 'A', - $or: [{ qty: { $lt: 30 } }, { item: { $regex: '^p' } }] - }); - // End Example 13 - assert.equal(2, yield cursor.count()); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('query embedded documents', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 14 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - qty: 25, - size: { h: 14, w: 21, uom: 'cm' }, - status: 'A' - }, - { - item: 'notebook', - qty: 50, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'A' - }, - { - item: 'paper', - qty: 100, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'D' - }, - { - item: 'planner', - qty: 75, - size: { h: 22.85, w: 30, uom: 'cm' }, - status: 'D' - }, - { - item: 'postcard', - qty: 45, - size: { h: 10, w: 15.25, uom: 'cm' }, - status: 'A' - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 14 - yield promise; - - // Start Example 15 - var cursor = db.collection('inventory').find({ - size: { h: 14, w: 21, uom: 'cm' } - }); - // End Example 15 - assert.equal(1, yield cursor.count()); - - /* eslint-disable */ - - // Start Example 16 - var cursor = db.collection('inventory').find({ - size: { w: 21, h: 14, uom: 'cm' } - }); - // End Example 16 - assert.equal(0, yield cursor.count()); - - // Start Example 17 - var cursor = db.collection('inventory').find({ - 'size.uom': 'in' - }); - // End Example 17 - assert.equal(2, yield cursor.count()); - - // Start Example 18 - var cursor = db.collection('inventory').find({ - 'size.h': { $lt: 15 } - }); - // End Example 18 - assert.equal(4, yield cursor.count()); - - // Start Example 19 - var cursor = db.collection('inventory').find({ - 'size.h': { $lt: 15 }, - 'size.uom': 'in', - status: 'D' - }); - // End Example 19 - assert.equal(1, yield cursor.count()); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('query arrays', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 20 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - qty: 25, - tags: ['blank', 'red'], - dim_cm: [14, 21] - }, - { - item: 'notebook', - qty: 50, - tags: ['red', 'blank'], - dim_cm: [14, 21] - }, - { - item: 'paper', - qty: 100, - tags: ['red', 'blank', 'plain'], - dim_cm: [14, 21] - }, - { - item: 'planner', - qty: 75, - tags: ['blank', 'red'], - dim_cm: [22.85, 30] - }, - { - item: 'postcard', - qty: 45, - tags: ['blue'], - dim_cm: [10, 15.25] - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 20 - yield promise; - - /* eslint-disable */ - - // Start Example 21 - var cursor = db.collection('inventory').find({ - tags: ['red', 'blank'] - }); - // End Example 21 - assert.equal(1, yield cursor.count()); - - // Start Example 22 - var cursor = db.collection('inventory').find({ - tags: { $all: ['red', 'blank'] } - }); - // End Example 22 - assert.equal(4, yield cursor.count()); - - // Start Example 23 - var cursor = db.collection('inventory').find({ - tags: 'red' - }); - // End Example 23 - assert.equal(4, yield cursor.count()); - - // Start Example 24 - var cursor = db.collection('inventory').find({ - dim_cm: { $gt: 25 } - }); - // End Example 24 - assert.equal(1, yield cursor.count()); - - // Start Example 25 - var cursor = db.collection('inventory').find({ - dim_cm: { $gt: 15, $lt: 20 } - }); - // End Example 25 - assert.equal(4, yield cursor.count()); - - // Start Example 26 - var cursor = db.collection('inventory').find({ - dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } - }); - // End Example 26 - assert.equal(1, yield cursor.count()); - - // Start Example 27 - var cursor = db.collection('inventory').find({ - 'dim_cm.1': { $gt: 25 } - }); - // End Example 27 - assert.equal(1, yield cursor.count()); - - // Start Example 28 - var cursor = db.collection('inventory').find({ - tags: { $size: 3 } - }); - // End Example 28 - assert.equal(1, yield cursor.count()); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('query array of documents', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 29 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - instock: [{ warehouse: 'A', qty: 5 }, { warehouse: 'C', qty: 15 }] - }, - { - item: 'notebook', - instock: [{ warehouse: 'C', qty: 5 }] - }, - { - item: 'paper', - instock: [{ warehouse: 'A', qty: 60 }, { warehouse: 'B', qty: 15 }] - }, - { - item: 'planner', - instock: [{ warehouse: 'A', qty: 40 }, { warehouse: 'B', qty: 5 }] - }, - { - item: 'postcard', - instock: [{ warehouse: 'B', qty: 15 }, { warehouse: 'C', qty: 35 }] - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 29 - yield promise; - - // Start Example 30 - var cursor = db.collection('inventory').find({ - instock: { warehouse: 'A', qty: 5 } - }); - // End Example 30 - assert.equal(1, yield cursor.count()); - - /* eslint-disable */ - - // Start Example 31 - var cursor = db.collection('inventory').find({ - instock: { qty: 5, warehouse: 'A' } - }); - // End Example 31 - assert.equal(0, yield cursor.count()); - - // Start Example 32 - var cursor = db.collection('inventory').find({ - 'instock.0.qty': { $lte: 20 } - }); - // End Example 32 - assert.equal(3, yield cursor.count()); - - // Start Example 33 - var cursor = db.collection('inventory').find({ - 'instock.qty': { $lte: 20 } - }); - // End Example 33 - assert.equal(5, yield cursor.count()); - - // Start Example 34 - var cursor = db.collection('inventory').find({ - instock: { $elemMatch: { qty: 5, warehouse: 'A' } } - }); - // End Example 34 - assert.equal(1, yield cursor.count()); - - // Start Example 35 - var cursor = db.collection('inventory').find({ - instock: { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } - }); - // End Example 35 - assert.equal(3, yield cursor.count()); - - // Start Example 36 - var cursor = db.collection('inventory').find({ - 'instock.qty': { $gt: 10, $lte: 20 } - }); - // End Example 36 - assert.equal(4, yield cursor.count()); - - // Start Example 37 - var cursor = db.collection('inventory').find({ - 'instock.qty': 5, - 'instock.warehouse': 'A' - }); - // End Example 37 - assert.equal(2, yield cursor.count()); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('query null', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 38 - db - .collection('inventory') - .insertMany([{ _id: 1, item: null }, { _id: 2 }]) - .then(function(result) { - processResult(result); - }); - // End Example 38 - yield promise; - - // Start Example 39 - var cursor = db.collection('inventory').find({ - item: null - }); - // End Example 39 - assert.equal(2, yield cursor.count()); - - /* eslint-disable */ - - // Start Example 40 - var cursor = db.collection('inventory').find({ - item: { $type: 10 } - }); - // End Example 40 - assert.equal(1, yield cursor.count()); - - // Start Example 41 - var cursor = db.collection('inventory').find({ - item: { $exists: false } - }); - // End Example 41 - assert.equal(1, yield cursor.count()); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('projection', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 42 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - status: 'A', - size: { h: 14, w: 21, uom: 'cm' }, - instock: [{ warehouse: 'A', qty: 5 }] - }, - { - item: 'notebook', - status: 'A', - size: { h: 8.5, w: 11, uom: 'in' }, - instock: [{ warehouse: 'C', qty: 5 }] - }, - { - item: 'paper', - status: 'D', - size: { h: 8.5, w: 11, uom: 'in' }, - instock: [{ warehouse: 'A', qty: 60 }] - }, - { - item: 'planner', - status: 'D', - size: { h: 22.85, w: 30, uom: 'cm' }, - instock: [{ warehouse: 'A', qty: 40 }] - }, - { - item: 'postcard', - status: 'A', - size: { h: 10, w: 15.25, uom: 'cm' }, - instock: [{ warehouse: 'B', qty: 15 }, { warehouse: 'C', qty: 35 }] - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 42 - yield promise; - - // Start Example 43 - var cursor = db.collection('inventory').find({ - status: 'A' - }); - // End Example 43 - assert.equal(3, yield cursor.count()); - - /* eslint-disable */ - - // Start Example 44 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ item: 1, status: 1 }); - // End Example 44 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.equal(undefined, doc.size); - assert.equal(undefined, doc.instock); - }); - - // Start Example 45 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ item: 1, status: 1, _id: 0 }); - // End Example 45 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.equal(undefined, doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.equal(undefined, doc.size); - assert.equal(undefined, doc.instock); - }); - - // Start Example 46 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ status: 0, instock: 0 }); - // End Example 46 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.equal(undefined, doc.status); - assert.ok(doc.size); - assert.equal(undefined, doc.instock); - }); - - // Start Example 47 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ item: 1, status: 1, 'size.uom': 1 }); - // End Example 47 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.ok(doc.size); - assert.equal(undefined, doc.instock); - var size = doc.size; - assert.ok(size.uom); - assert.equal(undefined, size.h); - assert.equal(undefined, size.w); - }); - - // Start Example 48 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ 'size.uom': 0 }); - // End Example 48 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.ok(doc.size); - assert.ok(doc.instock); - var size = doc.size; - assert.equal(undefined, size.uom); - assert.ok(size.h); - assert.ok(size.w); - }); - - // Start Example 49 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ item: 1, status: 1, 'instock.qty': 1 }); - // End Example 49 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.equal(undefined, doc.size); - doc.instock.forEach(function(subdoc) { - assert.equal(undefined, subdoc.warehouse); - assert.ok(subdoc.qty); - }); - }); - - // Start Example 50 - var cursor = db - .collection('inventory') - .find({ - status: 'A' - }) - .project({ item: 1, status: 1, instock: { $slice: -1 } }); - // End Example 50 - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.ok(doc._id); - assert.ok(doc.item); - assert.ok(doc.status); - assert.equal(undefined, doc.size); - assert.ok(doc.instock); - assert.equal(1, doc.instock.length); - }); - - /* eslint-enable */ - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('update and replace', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 51 - db - .collection('inventory') - .insertMany([ - { - item: 'canvas', - qty: 100, - size: { h: 28, w: 35.5, uom: 'cm' }, - status: 'A' - }, - { - item: 'journal', - qty: 25, - size: { h: 14, w: 21, uom: 'cm' }, - status: 'A' - }, - { - item: 'mat', - qty: 85, - size: { h: 27.9, w: 35.5, uom: 'cm' }, - status: 'A' - }, - { - item: 'mousepad', - qty: 25, - size: { h: 19, w: 22.85, uom: 'cm' }, - status: 'P' - }, - { - item: 'notebook', - qty: 50, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'P' - }, - { - item: 'paper', - qty: 100, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'D' - }, - { - item: 'planner', - qty: 75, - size: { h: 22.85, w: 30, uom: 'cm' }, - status: 'D' - }, - { - item: 'postcard', - qty: 45, - size: { h: 10, w: 15.25, uom: 'cm' }, - status: 'A' - }, - { - item: 'sketchbook', - qty: 80, - size: { h: 14, w: 21, uom: 'cm' }, - status: 'A' - }, - { - item: 'sketch pad', - qty: 95, - size: { h: 22.85, w: 30.5, uom: 'cm' }, - status: 'A' - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 51 - yield promise; - - promise = - // Start Example 52 - db - .collection('inventory') - .updateOne( - { item: 'paper' }, - { - $set: { 'size.uom': 'cm', status: 'P' }, - $currentDate: { lastModified: true } - } - ) - .then(function(result) { - processResult(result); - // process result - }); - // End Example 52 - yield promise; - var cursor = db.collection('inventory').find({ - item: 'paper' - }); - - var docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.equal('cm', doc.size.uom); - assert.equal('P', doc.status); - assert.ok(doc.lastModified); - }); - - promise = - // Start Example 53 - db - .collection('inventory') - .updateMany( - { qty: { $lt: 50 } }, - { - $set: { 'size.uom': 'in', status: 'P' }, - $currentDate: { lastModified: true } - } - ) - .then(function(result) { - processResult(result); - }); - // End Example 53 - yield promise; - cursor = db.collection('inventory').find({ - qty: { $lt: 50 } - }); - - docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.equal('in', doc.size.uom); - assert.equal('P', doc.status); - assert.ok(doc.lastModified); - }); - - promise = - // Start Example 54 - db - .collection('inventory') - .replaceOne( - { item: 'paper' }, - { - $set: { - item: 'paper', - instock: [{ warehouse: 'A', qty: 60 }, { warehouse: 'B', qty: 40 }] - }, - $unset: { - qty: '', - size: '', - status: '', - lastModified: '' - } - } - ) - .then(function(result) { - processResult(result); - }); - // End Example 54 - yield promise; - cursor = db - .collection('inventory') - .find({ - item: 'paper' - }) - .project({ _id: 0 }); - - docs = yield cursor.toArray(); - docs.forEach(function(doc) { - assert.equal(2, Object.keys(doc).length); - assert.ok(doc.item); - assert.ok(doc.instock); - assert.equal(2, doc.instock.length); - }); - - client.close(); - done(); - }); - }); - } - }); - - /** - * @ignore - */ - it('delete', { - metadata: { - requires: { - topology: ['single'], - mongodb: '>= 2.8.0' - } - }, - - // The actual test we wish to run - test: function(done) { - var configuration = this.configuration; - var MongoClient = configuration.require.MongoClient; - - // Connect and validate the server certificate - MongoClient.connect(configuration.url(), function(err, client) { - test.equal(null, err); - var db = client.db(configuration.db); - - co(function*() { - yield db.collection('inventory').deleteMany({}); - - var promise = - // Start Example 55 - db - .collection('inventory') - .insertMany([ - { - item: 'journal', - qty: 25, - size: { h: 14, w: 21, uom: 'cm' }, - status: 'A' - }, - { - item: 'notebook', - qty: 50, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'P' - }, - { - item: 'paper', - qty: 100, - size: { h: 8.5, w: 11, uom: 'in' }, - status: 'D' - }, - { - item: 'planner', - qty: 75, - size: { h: 22.85, w: 30, uom: 'cm' }, - status: 'D' - }, - { - item: 'postcard', - qty: 45, - size: { h: 10, w: 15.25, uom: 'cm' }, - status: 'A' - } - ]) - .then(function(result) { - processResult(result); - }); - // End Example 55 - yield promise; - - var cursor = db.collection('inventory').find({}); - assert.equal(5, yield cursor.count()); - - promise = - // Start Example 57 - db - .collection('inventory') - .deleteMany({ - status: 'A' - }) - .then(function(result) { - processResult(result); - }); - // End Example 57 - yield promise; - cursor = db.collection('inventory').find({}); - assert.equal(3, yield cursor.count()); - - promise = - // Start Example 58 - db - .collection('inventory') - .deleteOne({ - status: 'D' - }) - .then(function(result) { - processResult(result); - }); - // End Example 58 - yield promise; - cursor = db.collection('inventory').find({}); - assert.equal(2, yield cursor.count()); - - promise = - // Start Example 56 - db - .collection('inventory') - .deleteMany({}) - .then(function(result) { - processResult(result); - }); - // End Example 56 - yield promise; - cursor = db.collection('inventory').find({}); - assert.equal(0, yield cursor.count()); - - client.close(); - done(); - }); - }); - } - }); - - it('supports array filters when updating', { - metadata: { - requires: { - mongodb: '>=3.6.x', - topology: ['single'] - } - }, - - test: function(done) { - const configuration = this.configuration; - const MongoClient = configuration.newClient(); - - MongoClient.connect(function(err, client) { - const db = client.db(configuration.db); - const collection = db.collection('arrayFilterUpdateExample'); - - // 3. Exploiting the power of arrays - collection.updateOne( - { _id: 1 }, - { $set: { 'a.$[i].b': 2 } }, - { arrayFilters: [{ 'i.b': 0 }] }, - function updated(err, result) { - assert.equal(err, null); - assert.equal(typeof result, 'object'); - client.close(); - done(); - } - ); - }); - } - }); - - /** - * @ignore - */ - it('CausalConsistency', { - metadata: { - requires: { topology: ['single'], mongodb: '>=3.6.0' }, - sessions: { skipLeakTests: true } - }, - - test: function(done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { poolSize: 1 }); - - client.connect(function(err, client) { - const cleanup = e => { - client.close(); - done(e); - }; - - if (err) return cleanup(err); - - const db = client.db(configuration.db); - const collection = db.collection('causalConsistencyExample'); - const session = client.startSession({ causalConsistency: true }); - - collection.insertOne({ darmok: 'jalad' }, { session }); - collection.updateOne({ darmok: 'jalad' }, { $set: { darmok: 'tanagra' } }, { session }); - - collection.find({}, { session }).toArray(function(err, data) { - try { - expect(err).to.equal(null); - expect(data).to.exist; - } catch (e) { - return cleanup(e); - } - - cleanup(); - }); - }); - } - }); -}); diff --git a/test/functional/load_examples.js b/test/functional/load_examples.js new file mode 100644 index 00000000000..f41eb9db5ce --- /dev/null +++ b/test/functional/load_examples.js @@ -0,0 +1,27 @@ +'use strict'; + +let supportsAsyncAwait = false; + +try { + new Function('return (async function foo() {return await Promise.resolve(42);})();')(); + supportsAsyncAwait = true; +} catch (e) { + supportsAsyncAwait = false; +} + +if (supportsAsyncAwait) { + const fs = require('fs'); + const path = require('path'); + + fs + .readdirSync(path.resolve(__dirname, '..', 'examples')) + .filter(filePath => filePath.match(/.*\.js$/)) + .map(filePath => path.resolve(__dirname, '..', 'examples', filePath)) + .forEach(x => require(x)); +} else { + console.warn( + `Warning: Current Node Version ${ + process.version + } is not high enough to support running examples` + ); +}