mirror of https://gitee.com/bigwinds/arangodb
1057 lines
38 KiB
JavaScript
1057 lines
38 KiB
JavaScript
/*jshint strict: false, unused: false, maxlen: 200 */
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief ArangoCollection
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2011-2013 triagens GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
var ArangoCollection = require("@arangodb/arango-collection").ArangoCollection;
|
|
|
|
var arangodb = require("@arangodb");
|
|
|
|
var ArangoError = arangodb.ArangoError;
|
|
var sprintf = arangodb.sprintf;
|
|
var db = arangodb.db;
|
|
|
|
var simple = require("@arangodb/simple-query");
|
|
|
|
var SimpleQueryAll = simple.SimpleQueryAll;
|
|
var SimpleQueryByExample = simple.SimpleQueryByExample;
|
|
var SimpleQueryByCondition = simple.SimpleQueryByCondition;
|
|
var SimpleQueryRange = simple.SimpleQueryRange;
|
|
var SimpleQueryGeo = simple.SimpleQueryGeo;
|
|
var SimpleQueryNear = simple.SimpleQueryNear;
|
|
var SimpleQueryWithin = simple.SimpleQueryWithin;
|
|
var SimpleQueryWithinRectangle = simple.SimpleQueryWithinRectangle;
|
|
var SimpleQueryFulltext = simple.SimpleQueryFulltext;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- ArangoCollection
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- constants
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is corrupted
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_CORRUPTED = 0;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is new born
|
|
/// @deprecated
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_NEW_BORN = 1;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is unloaded
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_UNLOADED = 2;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is loaded
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_LOADED = 3;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is unloading
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_UNLOADING = 4;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is deleted
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_DELETED = 5;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief collection is currently loading
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.STATUS_LOADING = 6;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief document collection
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.TYPE_DOCUMENT = 2;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief edge collection
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.TYPE_EDGE = 3;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief prints a collection
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype._PRINT = function (context) {
|
|
var status = "unknown";
|
|
var type = "unknown";
|
|
var name = this.name();
|
|
|
|
switch (this.status()) {
|
|
case ArangoCollection.STATUS_NEW_BORN: status = "new born"; break;
|
|
case ArangoCollection.STATUS_UNLOADED: status = "unloaded"; break;
|
|
case ArangoCollection.STATUS_UNLOADING: status = "unloading"; break;
|
|
case ArangoCollection.STATUS_LOADED: status = "loaded"; break;
|
|
case ArangoCollection.STATUS_CORRUPTED: status = "corrupted"; break;
|
|
case ArangoCollection.STATUS_DELETED: status = "deleted"; break;
|
|
}
|
|
|
|
switch (this.type()) {
|
|
case ArangoCollection.TYPE_DOCUMENT: type = "document"; break;
|
|
case ArangoCollection.TYPE_EDGE: type = "edge"; break;
|
|
}
|
|
|
|
var colors = require("internal").COLORS;
|
|
var useColor = context.useColor;
|
|
|
|
context.output += "[ArangoCollection ";
|
|
if (useColor) { context.output += colors.COLOR_NUMBER; }
|
|
context.output += this._id;
|
|
if (useColor) { context.output += colors.COLOR_RESET; }
|
|
context.output += ", \"";
|
|
if (useColor) { context.output += colors.COLOR_STRING; }
|
|
context.output += name || "unknown";
|
|
if (useColor) { context.output += colors.COLOR_RESET; }
|
|
context.output += "\" (type " + type + ", status " + status + ")]";
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief converts into a string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.toString = function () {
|
|
return "[ArangoCollection: " + this._id + "]";
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs an all query for a collection
|
|
/// @startDocuBlock collectionAll
|
|
/// `collection.all()`
|
|
///
|
|
/// Fetches all documents from a collection and returns a cursor. You can use
|
|
/// *toArray*, *next*, or *hasNext* to access the result. The result
|
|
/// can be limited using the *skip* and *limit* operator.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// Use *toArray* to get all documents at once:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{001_collectionAll}
|
|
/// ~ db._create("five");
|
|
/// db.five.save({ name : "one" });
|
|
/// db.five.save({ name : "two" });
|
|
/// db.five.save({ name : "three" });
|
|
/// db.five.save({ name : "four" });
|
|
/// db.five.save({ name : "five" });
|
|
/// db.five.all().toArray();
|
|
/// ~ db._drop("five");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// Use *limit* to restrict the documents:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{002_collectionAllNext}
|
|
/// ~ db._create("five");
|
|
/// db.five.save({ name : "one" });
|
|
/// db.five.save({ name : "two" });
|
|
/// db.five.save({ name : "three" });
|
|
/// db.five.save({ name : "four" });
|
|
/// db.five.save({ name : "five" });
|
|
/// db.five.all().limit(2).toArray();
|
|
/// ~ db._drop("five");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.all = function () {
|
|
return new SimpleQueryAll(this);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a query-by-example for a collection
|
|
/// @startDocuBlock collectionByExample
|
|
/// `collection.byExample(example)`
|
|
///
|
|
/// Fetches all documents from a collection that match the specified
|
|
/// example and returns a cursor.
|
|
///
|
|
/// You can use *toArray*, *next*, or *hasNext* to access the
|
|
/// result. The result can be limited using the *skip* and *limit*
|
|
/// operator.
|
|
///
|
|
/// An attribute name of the form *a.b* is interpreted as attribute path,
|
|
/// not as attribute. If you use
|
|
///
|
|
/// *{ a : { c : 1 } }*
|
|
///
|
|
/// as example, then you will find all documents, such that the attribute
|
|
/// *a* contains a document of the form *{c : 1 }*. For example the document
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }*
|
|
///
|
|
/// will match, but the document
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will not.
|
|
///
|
|
/// However, if you use
|
|
///
|
|
/// *{ a.c : 1 }*,
|
|
///
|
|
/// then you will find all documents, which contain a sub-document in *a*
|
|
/// that has an attribute *c* of value *1*. Both the following documents
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }* and
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will match.
|
|
///
|
|
/// `collection.byExample(path1, value1, ...)`
|
|
///
|
|
/// As alternative you can supply an array of paths and values.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// Use *toArray* to get all documents at once:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{003_collectionByExample}
|
|
/// ~ db._create("users");
|
|
/// db.users.save({ name: "Gerhard" });
|
|
/// db.users.save({ name: "Helmut" });
|
|
/// db.users.save({ name: "Angela" });
|
|
/// db.users.all().toArray();
|
|
/// db.users.byExample({ "_id" : "users/20" }).toArray();
|
|
/// db.users.byExample({ "name" : "Gerhard" }).toArray();
|
|
/// db.users.byExample({ "name" : "Helmut", "_id" : "users/15" }).toArray();
|
|
/// ~ db._drop("users");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// Use *next* to loop over all documents:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{004_collectionByExampleNext}
|
|
/// ~ db._create("users");
|
|
/// db.users.save({ name: "Gerhard" });
|
|
/// db.users.save({ name: "Helmut" });
|
|
/// db.users.save({ name: "Angela" });
|
|
/// var a = db.users.byExample( {"name" : "Angela" } );
|
|
/// while (a.hasNext()) print(a.next());
|
|
/// ~ db._drop("users");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.byExample = function (example) {
|
|
var e;
|
|
var i;
|
|
|
|
// example is given as only argument
|
|
if (arguments.length === 1) {
|
|
e = example;
|
|
}
|
|
|
|
// example is given as list
|
|
else {
|
|
e = {};
|
|
|
|
// create a REAL array, otherwise JSON.stringify will fail
|
|
for (i = 0; i < arguments.length; i += 2) {
|
|
e[arguments[i]] = arguments[i + 1];
|
|
}
|
|
}
|
|
|
|
return new SimpleQueryByExample(this, e);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a query-by-example using a hash index
|
|
/// @startDocuBLock collectionByExampleHash
|
|
/// `collection.byExampleHash(index, example)`
|
|
///
|
|
/// Selects all documents from the specified hash index that match the
|
|
/// specified example and returns a cursor.
|
|
///
|
|
/// You can use *toArray*, *next*, or *hasNext* to access the
|
|
/// result. The result can be limited using the *skip* and *limit*
|
|
/// operator.
|
|
///
|
|
/// An attribute name of the form *a.b* is interpreted as attribute path,
|
|
/// not as attribute. If you use
|
|
///
|
|
/// *{ a : { c : 1 } }*
|
|
///
|
|
/// as example, then you will find all documents, such that the attribute
|
|
/// *a* contains a document of the form *{c : 1 }*. For example the document
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }*
|
|
///
|
|
/// will match, but the document
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will not.
|
|
///
|
|
/// However, if you use
|
|
///
|
|
/// *{ a.c : 1 }*,
|
|
///
|
|
/// then you will find all documents, which contain a sub-document in *a*
|
|
/// that has an attribute @LIT{c} of value *1*. Both the following documents
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }* and
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will match.
|
|
///
|
|
/// `collection.byExampleHash(index-id, path1, value1, ...)`
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.byExampleHash = function (index, example) {
|
|
var sq = this.byExample(example);
|
|
sq._index = index;
|
|
sq._type = "hash";
|
|
|
|
return sq;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a query-by-example using a skiplist index
|
|
/// @startDocuBlock collectionByExampleSkiplist
|
|
/// `collection.byExampleSkiplist(index, example)`
|
|
///
|
|
/// Selects all documents from the specified skiplist index that match the
|
|
/// specified example and returns a cursor.
|
|
///
|
|
/// You can use *toArray*, *next*, or *hasNext* to access the
|
|
/// result. The result can be limited using the *skip* and *limit*
|
|
/// operator.
|
|
///
|
|
/// An attribute name of the form *a.b* is interpreted as attribute path,
|
|
/// not as attribute. If you use
|
|
///
|
|
/// *{ a : { c : 1 } }*
|
|
///
|
|
/// as example, then you will find all documents, such that the attribute
|
|
/// *a* contains a document of the form *{c : 1 }*. For example the document
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }*
|
|
///
|
|
/// will match, but the document
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will not.
|
|
///
|
|
/// However, if you use
|
|
///
|
|
/// *{ a.c : 1 }*,
|
|
///
|
|
/// then you will find all documents, which contain a sub-document in *a*
|
|
/// that has an attribute @LIT{c} of value *1*. Both the following documents
|
|
///
|
|
/// *{ a : { c : 1 }, b : 1 }*and
|
|
///
|
|
/// *{ a : { c : 1, b : 1 } }*
|
|
///
|
|
/// will match.
|
|
///
|
|
/// `collection.byExampleSkiplist(index, path1, value1, ...)`
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.byExampleSkiplist = function (index, example) {
|
|
var sq = this.byExample(example);
|
|
sq._index = index;
|
|
sq._type = "skiplist";
|
|
|
|
return sq;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a query-by-condition using a skiplist index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.byConditionSkiplist = function (index, condition) {
|
|
var sq = new SimpleQueryByCondition(this, condition);
|
|
sq._index = index;
|
|
sq._type = "skiplist";
|
|
|
|
return sq;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a range query for a collection
|
|
/// @startDocuBlock collectionRange
|
|
/// `collection.range(attribute, left, right)`
|
|
///
|
|
/// Returns all documents from a collection such that the *attribute* is
|
|
/// greater or equal than *left* and strictly less than *right*.
|
|
///
|
|
/// You can use *toArray*, *next*, or *hasNext* to access the
|
|
/// result. The result can be limited using the *skip* and *limit*
|
|
/// operator.
|
|
///
|
|
/// An attribute name of the form *a.b* is interpreted as attribute path,
|
|
/// not as attribute.
|
|
///
|
|
/// For range queries it is required that a skiplist index is present for the
|
|
/// queried attribute. If no skiplist index is present on the attribute, an
|
|
/// error will be thrown.
|
|
///
|
|
/// Note: the *range* simple query function is **deprecated** as of ArangoDB 2.6.
|
|
/// The function may be removed in future versions of ArangoDB. The preferred
|
|
/// way for retrieving documents from a collection within a specific range
|
|
/// is to use an AQL query as follows:
|
|
///
|
|
/// FOR doc IN @@collection
|
|
/// FILTER doc.value >= @left && doc.value < @right
|
|
/// LIMIT @skip, @limit
|
|
/// RETURN doc
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// Use *toArray* to get all documents at once:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{005_collectionRange}
|
|
/// ~ db._create("old");
|
|
/// db.old.ensureIndex({ type: "skiplist", fields: [ "age" ] });
|
|
/// db.old.save({ age: 15 });
|
|
/// db.old.save({ age: 25 });
|
|
/// db.old.save({ age: 30 });
|
|
/// db.old.range("age", 10, 30).toArray();
|
|
/// ~ db._drop("old")
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.range = function (name, left, right) {
|
|
return new SimpleQueryRange(this, name, left, right, 0);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a closed range query for a collection
|
|
/// @startDocuBlock collectionClosedRange
|
|
/// `collection.closedRange(attribute, left, right)`
|
|
///
|
|
/// Returns all documents of a collection such that the *attribute* is
|
|
/// greater or equal than *left* and less or equal than *right*.
|
|
///
|
|
/// You can use *toArray*, *next*, or *hasNext* to access the
|
|
/// result. The result can be limited using the *skip* and *limit*
|
|
/// operator.
|
|
///
|
|
/// An attribute name of the form *a.b* is interpreted as attribute path,
|
|
/// not as attribute.
|
|
///
|
|
/// Note: the *closedRange* simple query function is **deprecated** as of ArangoDB 2.6.
|
|
/// The function may be removed in future versions of ArangoDB. The preferred
|
|
/// way for retrieving documents from a collection within a specific range
|
|
/// is to use an AQL query as follows:
|
|
///
|
|
/// FOR doc IN @@collection
|
|
/// FILTER doc.value >= @left && doc.value <= @right
|
|
/// LIMIT @skip, @limit
|
|
/// RETURN doc
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// Use *toArray* to get all documents at once:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{006_collectionClosedRange}
|
|
/// ~ db._create("old");
|
|
/// db.old.ensureIndex({ type: "skiplist", fields: [ "age" ] });
|
|
/// db.old.save({ age: 15 });
|
|
/// db.old.save({ age: 25 });
|
|
/// db.old.save({ age: 30 });
|
|
/// db.old.closedRange("age", 10, 30).toArray();
|
|
/// ~ db._drop("old")
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.closedRange = function (name, left, right) {
|
|
return new SimpleQueryRange(this, name, left, right, 1);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a geo index selection
|
|
/// @startDocuBlock collectionGeo
|
|
/// `collection.geo(location-attribute)`
|
|
///
|
|
/// Looks up a geo index defined on attribute *location_attribute*.
|
|
///
|
|
/// Returns a geo index object if an index was found. The `near` or
|
|
/// `within` operators can then be used to execute a geo-spatial query on
|
|
/// this particular index.
|
|
///
|
|
/// This is useful for collections with multiple defined geo indexes.
|
|
///
|
|
/// `collection.geo(location_attribute, true)`
|
|
///
|
|
/// Looks up a geo index on a compound attribute *location_attribute*.
|
|
///
|
|
/// Returns a geo index object if an index was found. The `near` or
|
|
/// `within` operators can then be used to execute a geo-spatial query on
|
|
/// this particular index.
|
|
///
|
|
/// `collection.geo(latitude_attribute, longitude_attribute)`
|
|
///
|
|
/// Looks up a geo index defined on the two attributes *latitude_attribute*
|
|
/// and *longitude-attribute*.
|
|
///
|
|
/// Returns a geo index object if an index was found. The `near` or
|
|
/// `within` operators can then be used to execute a geo-spatial query on
|
|
/// this particular index.
|
|
///
|
|
/// Note: the *geo* simple query helper function is **deprecated** as of ArangoDB
|
|
/// 2.6. The function may be removed in future versions of ArangoDB. The preferred
|
|
/// way for running geo queries is to use their AQL equivalents.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// Assume you have a location stored as list in the attribute *home*
|
|
/// and a destination stored in the attribute *work*. Then you can use the
|
|
/// `geo` operator to select which geo-spatial attributes (and thus which
|
|
/// index) to use in a `near` query.
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{geoIndexSimpleQuery}
|
|
/// ~db._create("complex")
|
|
/// |for (i = -90; i <= 90; i += 10) {
|
|
/// | for (j = -180; j <= 180; j += 10) {
|
|
/// | db.complex.save({ name : "Name/" + i + "/" + j,
|
|
/// | home : [ i, j ],
|
|
/// | work : [ -i, -j ] });
|
|
/// | }
|
|
/// |}
|
|
///
|
|
/// db.complex.near(0, 170).limit(5); // xpError(ERROR_QUERY_GEO_INDEX_MISSING)
|
|
/// db.complex.ensureIndex({ type: "geo", fields: [ "home" ] });
|
|
/// db.complex.near(0, 170).limit(5).toArray();
|
|
/// db.complex.geo("work").near(0, 170).limit(5); // xpError(ERROR_QUERY_GEO_INDEX_MISSING)
|
|
/// db.complex.ensureIndex({ type: "geo", fields: [ "work" ] });
|
|
/// db.complex.geo("work").near(0, 170).limit(5).toArray();
|
|
/// ~ db._drop("complex");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.geo = function(loc, order) {
|
|
var idx;
|
|
|
|
var locateGeoIndex1 = function(collection, loc, order) {
|
|
var inds = collection.getIndexes();
|
|
var i;
|
|
|
|
for (i = 0; i < inds.length; ++i) {
|
|
var index = inds[i];
|
|
|
|
if (index.type === "geo1") {
|
|
if (index.fields[0] === loc && index.geoJson === order) {
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
var locateGeoIndex2 = function(collection, lat, lon) {
|
|
var inds = collection.getIndexes();
|
|
var i;
|
|
|
|
for (i = 0; i < inds.length; ++i) {
|
|
var index = inds[i];
|
|
|
|
if (index.type === "geo2") {
|
|
if (index.fields[0] === lat && index.fields[1] === lon) {
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
if (order === undefined) {
|
|
if (typeof loc === "object") {
|
|
idx = this.index(loc);
|
|
}
|
|
else {
|
|
idx = locateGeoIndex1(this, loc, false);
|
|
}
|
|
}
|
|
else if (typeof order === "boolean") {
|
|
idx = locateGeoIndex1(this, loc, order);
|
|
}
|
|
else {
|
|
idx = locateGeoIndex2(this, loc, order);
|
|
}
|
|
|
|
if (idx === null) {
|
|
var err = new ArangoError();
|
|
err.errorNum = arangodb.errors.ERROR_QUERY_GEO_INDEX_MISSING.code;
|
|
err.errorMessage = require("internal").sprintf(arangodb.errors.ERROR_QUERY_GEO_INDEX_MISSING.message, this.name());
|
|
throw err;
|
|
}
|
|
|
|
return new SimpleQueryGeo(this, idx.id);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a near query for a collection
|
|
/// @startDocuBlock collectionNear
|
|
/// `collection.near(latitude, longitude)`
|
|
///
|
|
/// The returned list is sorted according to the distance, with the nearest
|
|
/// document to the coordinate (*latitude*, *longitude*) coming first.
|
|
/// If there are near documents of equal distance, documents are chosen randomly
|
|
/// from this set until the limit is reached. It is possible to change the limit
|
|
/// using the *limit* operator.
|
|
///
|
|
/// In order to use the *near* operator, a geo index must be defined for the
|
|
/// collection. This index also defines which attribute holds the coordinates
|
|
/// for the document. If you have more then one geo-spatial index, you can use
|
|
/// the *geo* operator to select a particular index.
|
|
///
|
|
/// *Note*: `near` does not support negative skips.
|
|
// However, you can still use `limit` followed to skip.
|
|
///
|
|
/// `collection.near(latitude, longitude).limit(limit)`
|
|
///
|
|
/// Limits the result to limit documents instead of the default 100.
|
|
///
|
|
/// *Note*: Unlike with multiple explicit limits, `limit` will raise
|
|
/// the implicit default limit imposed by `within`.
|
|
///
|
|
/// `collection.near(latitude, longitude).distance()`
|
|
///
|
|
/// This will add an attribute `distance` to all documents returned, which
|
|
/// contains the distance between the given point and the document in meters.
|
|
///
|
|
/// `collection.near(latitude, longitude).distance(name)`
|
|
///
|
|
/// This will add an attribute *name* to all documents returned, which
|
|
/// contains the distance between the given point and the document in meters.
|
|
///
|
|
/// Note: the *near* simple query function is **deprecated** as of ArangoDB 2.6.
|
|
/// The function may be removed in future versions of ArangoDB. The preferred
|
|
/// way for retrieving documents from a collection using the near operator is
|
|
/// to use the AQL *NEAR* function in an [AQL query](../Aql/GeoFunctions.md) as follows:
|
|
///
|
|
/// FOR doc IN NEAR(@@collection, @latitude, @longitude, @limit)
|
|
/// RETURN doc
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// To get the nearest two locations:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{007_collectionNear}
|
|
/// ~ db._create("geo");
|
|
/// db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
|
|
/// |for (var i = -90; i <= 90; i += 10) {
|
|
/// | for (var j = -180; j <= 180; j += 10) {
|
|
/// | db.geo.save({
|
|
/// | name : "Name/" + i + "/" + j,
|
|
/// | loc: [ i, j ] });
|
|
/// } }
|
|
/// db.geo.near(0, 0).limit(2).toArray();
|
|
/// ~ db._drop("geo");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// If you need the distance as well, then you can use the `distance`
|
|
/// operator:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{008_collectionNearDistance}
|
|
/// ~ db._create("geo");
|
|
/// db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
|
|
/// |for (var i = -90; i <= 90; i += 10) {
|
|
/// | for (var j = -180; j <= 180; j += 10) {
|
|
/// | db.geo.save({
|
|
/// | name : "Name/" + i + "/" + j,
|
|
/// | loc: [ i, j ] });
|
|
/// } }
|
|
/// db.geo.near(0, 0).distance().limit(2).toArray();
|
|
/// ~ db._drop("geo");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.near = function (lat, lon) {
|
|
return new SimpleQueryNear(this, lat, lon);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructs a within query for a collection
|
|
/// @startDocuBlock collectionWithin
|
|
/// `collection.within(latitude, longitude, radius)`
|
|
///
|
|
/// This will find all documents within a given radius around the coordinate
|
|
/// (*latitude*, *longitude*). The returned array is sorted by distance,
|
|
/// beginning with the nearest document.
|
|
///
|
|
/// In order to use the *within* operator, a geo index must be defined for the
|
|
/// collection. This index also defines which attribute holds the coordinates
|
|
/// for the document. If you have more then one geo-spatial index, you can use
|
|
/// the `geo` operator to select a particular index.
|
|
///
|
|
///
|
|
/// `collection.within(latitude, longitude, radius).distance()`
|
|
///
|
|
/// This will add an attribute `_distance` to all documents returned, which
|
|
/// contains the distance between the given point and the document in meters.
|
|
///
|
|
/// `collection.within(latitude, longitude, radius).distance(name)`
|
|
///
|
|
/// This will add an attribute *name* to all documents returned, which
|
|
/// contains the distance between the given point and the document in meters.
|
|
///
|
|
/// Note: the *within* simple query function is **deprecated** as of ArangoDB 2.6.
|
|
/// The function may be removed in future versions of ArangoDB. The preferred
|
|
/// way for retrieving documents from a collection using the within operator is
|
|
/// to use the AQL *WITHIN* function in an [AQL query](../Aql/GeoFunctions.md) as follows:
|
|
///
|
|
/// FOR doc IN WITHIN(@@collection, @latitude, @longitude, @radius, @distanceAttributeName)
|
|
/// RETURN doc
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// To find all documents within a radius of 2000 km use:
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{009_collectionWithin}
|
|
/// ~ db._create("geo");
|
|
/// ~ db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
|
|
/// |~ for (var i = -90; i <= 90; i += 10) {
|
|
/// | for (var j = -180; j <= 180; j += 10) {
|
|
/// db.geo.save({ name : "Name/" + i + "/" + j, loc: [ i, j ] }); } }
|
|
/// db.geo.within(0, 0, 2000 * 1000).distance().toArray();
|
|
/// ~ db._drop("geo");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.within = function (lat, lon, radius) {
|
|
return new SimpleQueryWithin(this, lat, lon, radius);
|
|
};
|
|
|
|
ArangoCollection.prototype.withinRectangle = function (lat1, lon1, lat2, lon2) {
|
|
return new SimpleQueryWithinRectangle(this, lat1, lon1, lat2, lon2);
|
|
};
|
|
|
|
ArangoCollection.prototype.fulltext = function (attribute, query, iid) {
|
|
return new SimpleQueryFulltext(this, attribute, query, iid);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @startDocuBlock collectionIterate
|
|
/// @brief iterates over some elements of a collection
|
|
/// `collection.iterate(iterator, options)`
|
|
///
|
|
/// Iterates over some elements of the collection and apply the function
|
|
/// *iterator* to the elements. The function will be called with the
|
|
/// document as first argument and the current number (starting with 0)
|
|
/// as second argument.
|
|
///
|
|
/// *options* must be an object with the following attributes:
|
|
///
|
|
/// - *limit* (optional, default none): use at most *limit* documents.
|
|
///
|
|
/// - *probability* (optional, default all): a number between *0* and
|
|
/// *1*. Documents are chosen with this probability.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{accessViaGeoIndex}
|
|
/// ~db._create("example")
|
|
/// |for (i = -90; i <= 90; i += 10) {
|
|
/// | for (j = -180; j <= 180; j += 10) {
|
|
/// | db.example.save({ name : "Name/" + i + "/" + j,
|
|
/// | home : [ i, j ],
|
|
/// | work : [ -i, -j ] });
|
|
/// | }
|
|
/// |}
|
|
///
|
|
/// db.example.ensureIndex({ type: "geo", fields: [ "home" ] });
|
|
/// |items = db.example.getIndexes().map(function(x) { return x.id; });
|
|
/// db.example.index(items[1]);
|
|
/// ~ db._drop("example");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
///
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.iterate = function (iterator, options) {
|
|
var probability = 1.0;
|
|
var limit = null;
|
|
var stmt;
|
|
var cursor;
|
|
var pos;
|
|
|
|
// TODO: this is not optimal for the client, there should be an HTTP call handling
|
|
// everything on the server
|
|
|
|
if (options !== undefined) {
|
|
if (options.hasOwnProperty("probability")) {
|
|
probability = options.probability;
|
|
}
|
|
|
|
if (options.hasOwnProperty("limit")) {
|
|
limit = options.limit;
|
|
}
|
|
}
|
|
|
|
if (limit === null) {
|
|
if (probability >= 1.0) {
|
|
cursor = this.all();
|
|
}
|
|
else {
|
|
stmt = sprintf("FOR d IN %s FILTER rand() >= @prob RETURN d", this.name());
|
|
stmt = db._createStatement({ query: stmt });
|
|
|
|
if (probability < 1.0) {
|
|
stmt.bind("prob", probability);
|
|
}
|
|
|
|
cursor = stmt.execute();
|
|
}
|
|
}
|
|
else {
|
|
if (typeof limit !== "number") {
|
|
var error = new ArangoError();
|
|
error.errorNum = arangodb.errors.ERROR_ILLEGAL_NUMBER.code;
|
|
error.errorMessage = "expecting a number, got " + String(limit);
|
|
|
|
throw error;
|
|
}
|
|
|
|
if (probability >= 1.0) {
|
|
cursor = this.all().limit(limit);
|
|
}
|
|
else {
|
|
stmt = sprintf("FOR d IN %s FILTER rand() >= @prob LIMIT %d RETURN d",
|
|
this.name(), limit);
|
|
stmt = db._createStatement({ query: stmt });
|
|
|
|
if (probability < 1.0) {
|
|
stmt.bind("prob", probability);
|
|
}
|
|
|
|
cursor = stmt.execute();
|
|
}
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
while (cursor.hasNext()) {
|
|
var document = cursor.next();
|
|
|
|
iterator(document, pos);
|
|
|
|
pos++;
|
|
}
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- document methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief removes documents matching an example
|
|
/// @startDocuBlock documentsCollectionRemoveByExample
|
|
/// `collection.removeByExample(example)`
|
|
///
|
|
/// Removes all documents matching an example.
|
|
///
|
|
/// `collection.removeByExample(document, waitForSync)`
|
|
///
|
|
/// The optional *waitForSync* parameter can be used to force synchronization
|
|
/// of the document deletion operation to disk even in case that the
|
|
/// *waitForSync* flag had been disabled for the entire collection. Thus,
|
|
/// the *waitForSync* parameter can be used to force synchronization of just
|
|
/// specific operations. To use this, set the *waitForSync* parameter to
|
|
/// *true*. If the *waitForSync* parameter is not specified or set to
|
|
/// *false*, then the collection's default *waitForSync* behavior is
|
|
/// applied. The *waitForSync* parameter cannot be used to disable
|
|
/// synchronization for collections that have a default *waitForSync* value
|
|
/// of *true*.
|
|
///
|
|
/// `collection.removeByExample(document, waitForSync, limit)`
|
|
///
|
|
/// The optional *limit* parameter can be used to restrict the number of
|
|
/// removals to the specified value. If *limit* is specified but less than the
|
|
/// number of documents in the collection, it is undefined which documents are
|
|
/// removed.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{010_documentsCollectionRemoveByExample}
|
|
/// ~ db._create("example");
|
|
/// ~ db.example.save({ Hello : "world" });
|
|
/// db.example.removeByExample( {Hello : "world"} );
|
|
/// ~ db._drop("example");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.removeByExample = function (example, waitForSync, limit) {
|
|
throw "cannot call abstract removeByExample function";
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief replaces documents matching an example
|
|
/// @startDocuBlock documentsCollectionReplaceByExample
|
|
/// `collection.replaceByExample(example, newValue)`
|
|
///
|
|
/// Replaces all documents matching an example with a new document body.
|
|
/// The entire document body of each document matching the *example* will be
|
|
/// replaced with *newValue*. The document meta-attributes such as *_id*,
|
|
/// *_key*, *_from*, *_to* will not be replaced.
|
|
///
|
|
/// `collection.replaceByExample(document, newValue, waitForSync)`
|
|
///
|
|
/// The optional *waitForSync* parameter can be used to force synchronization
|
|
/// of the document replacement operation to disk even in case that the
|
|
/// *waitForSync* flag had been disabled for the entire collection. Thus,
|
|
/// the *waitForSync* parameter can be used to force synchronization of just
|
|
/// specific operations. To use this, set the *waitForSync* parameter to
|
|
/// *true*. If the *waitForSync* parameter is not specified or set to
|
|
/// *false*, then the collection's default *waitForSync* behavior is
|
|
/// applied. The *waitForSync* parameter cannot be used to disable
|
|
/// synchronization for collections that have a default *waitForSync* value
|
|
/// of *true*.
|
|
///
|
|
/// `collection.replaceByExample(document, newValue, waitForSync, limit)`
|
|
///
|
|
/// The optional *limit* parameter can be used to restrict the number of
|
|
/// replacements to the specified value. If *limit* is specified but less than
|
|
/// the number of documents in the collection, it is undefined which documents are
|
|
/// replaced.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{011_documentsCollectionReplaceByExample}
|
|
/// ~ db._create("example");
|
|
/// db.example.save({ Hello : "world" });
|
|
/// db.example.replaceByExample({ Hello: "world" }, {Hello: "mars"}, false, 5);
|
|
/// ~ db._drop("example");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.replaceByExample = function (example, newValue, waitForSync, limit) {
|
|
throw "cannot call abstract replaceByExample function";
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief partially updates documents matching an example
|
|
/// @startDocuBlock documentsCollectionUpdateByExample
|
|
/// `collection.updateByExample(example, newValue)`
|
|
///
|
|
/// Partially updates all documents matching an example with a new document body.
|
|
/// Specific attributes in the document body of each document matching the
|
|
/// *example* will be updated with the values from *newValue*.
|
|
/// The document meta-attributes such as *_id*, *_key*, *_from*,
|
|
/// *_to* cannot be updated.
|
|
///
|
|
/// Partial update could also be used to append new fields,
|
|
/// if there were no old field with same name.
|
|
///
|
|
/// `collection.updateByExample(document, newValue, keepNull, waitForSync)`
|
|
///
|
|
/// The optional *keepNull* parameter can be used to modify the behavior when
|
|
/// handling *null* values. Normally, *null* values are stored in the
|
|
/// database. By setting the *keepNull* parameter to *false*, this behavior
|
|
/// can be changed so that all attributes in *data* with *null* values will
|
|
/// be removed from the target document.
|
|
///
|
|
/// The optional *waitForSync* parameter can be used to force synchronization
|
|
/// of the document replacement operation to disk even in case that the
|
|
/// *waitForSync* flag had been disabled for the entire collection. Thus,
|
|
/// the *waitForSync* parameter can be used to force synchronization of just
|
|
/// specific operations. To use this, set the *waitForSync* parameter to
|
|
/// *true*. If the *waitForSync* parameter is not specified or set to
|
|
/// *false*, then the collection's default *waitForSync* behavior is
|
|
/// applied. The *waitForSync* parameter cannot be used to disable
|
|
/// synchronization for collections that have a default *waitForSync* value
|
|
/// of *true*.
|
|
///
|
|
/// `collection.updateByExample(document, newValue, keepNull, waitForSync, limit)`
|
|
///
|
|
/// The optional *limit* parameter can be used to restrict the number of
|
|
/// updates to the specified value. If *limit* is specified but less than
|
|
/// the number of documents in the collection, it is undefined which documents are
|
|
/// updated.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @EXAMPLE_ARANGOSH_OUTPUT{012_documentsCollectionUpdateByExample}
|
|
/// ~ db._create("example");
|
|
/// db.example.save({ Hello : "world", foo : "bar" });
|
|
/// db.example.updateByExample({ Hello: "world" }, { Hello: "foo", World: "bar" }, false);
|
|
/// db.example.byExample({ Hello: "foo" }).toArray()
|
|
/// ~ db._drop("example");
|
|
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
|
/// @endDocuBlock
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ArangoCollection.prototype.updateByExample = function (example, newValue, keepNull, waitForSync, limit) {
|
|
throw "cannot call abstract updateExample function";
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- END-OF-FILE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @}\\|/\\*jslint"
|
|
// End:
|