GeoNearDocumentSource.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. "use strict";
  2. var DocumentSource = require("./DocumentSource"),
  3. FieldPath = require("../FieldPath");
  4. /**
  5. * @class GeoNearDocumentSource
  6. * @namespace mungedb-aggregate.pipeline.documentSources
  7. * @module mungedb-aggregate
  8. * @constructor
  9. * @param [ctx] {ExpressionContext}
  10. **/
  11. var GeoNearDocumentSource = module.exports = function GeoNearDocumentSource(ctx) {
  12. if (arguments.length > 1) throw new Error("up to one arg expected");
  13. base.call(this, ctx);
  14. // mongo defaults
  15. this.coordsIsArray = false;
  16. this.limit = 100;
  17. this.maxDistance = -1.0;
  18. this.spherical = false;
  19. this.distanceMultiplier = 1.0;
  20. this.uniqueDocs = true;
  21. }, klass = GeoNearDocumentSource, base = require("./DocumentSource"), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}}); //jshint ignore:line
  22. klass.geoNearName = "$geoNear";
  23. klass.create = function create(expCtx) {
  24. return new GeoNearDocumentSource(expCtx);
  25. };
  26. proto.getSourceName = function() {
  27. return klass.geoNearName;
  28. };
  29. proto.getNext = function getNext() {
  30. throw new Error("Not implemented yet");
  31. };
  32. proto.setSource = function(docSource) {
  33. throw new Error("code 16602; $geoNear is only allowed as the first pipeline stage");
  34. };
  35. proto.isValidInitialSource = function() {
  36. return true;
  37. };
  38. proto.serialize = function(explain) {
  39. var result = {};
  40. if (this.coordsIsArray)
  41. result.near = this.near;
  42. else
  43. result.near = [this.near];
  44. // not in buildGeoNearCmd
  45. result.distanceField = this.distanceField.getPath(false);
  46. result.limit = this.limit;
  47. if (this.maxDistance > 0)
  48. result.maxDistance = this.maxDistance;
  49. if (this.query)
  50. result.query = this.query;
  51. if (this.spherical)
  52. result.spherical = this.spherical;
  53. if (this.distanceMultiplier)
  54. result.distanceMultiplier = this.distanceMultiplier;
  55. if (this.includeLocs) {
  56. if (typeof this.includeLocs !== "string")
  57. throw new Error("code 16607; $geoNear requires that \"includeLocs\" option is a String");
  58. result.includeLocs = this.includeLocs.getPath(false);
  59. }
  60. if (this.uniqueDocs)
  61. result.uniqueDocs = this.uniqueDocs;
  62. var sourceName = this.getSourceName(),
  63. returnObj = {};
  64. returnObj[sourceName] = result;
  65. return returnObj;
  66. };
  67. klass.createFromJson = function(jsonElement, ctx) {
  68. var out = new GeoNearDocumentSource(ctx);
  69. out.parseOptions(jsonElement);
  70. return out;
  71. };
  72. proto.parseOptions = function(options) {
  73. // near and distanceField are required
  74. if (!options.near || !Array.isArray(options.near))
  75. throw new Error("code 16605; $geoNear requires a \"near\" option as an Array");
  76. this.coordsIsArray = options.near instanceof Array;
  77. if (typeof options.distanceField !== "string")
  78. throw new Error("code 16606: $geoNear a \"distanceNear\" option as a String");
  79. this.distanceField = new FieldPath(options.distanceField);
  80. // remaining fields are optional
  81. // num and limits are synonyms
  82. if (typeof options.limit === "number")
  83. this.limit = options.limit;
  84. if (typeof options.num === "number")
  85. this.limit = options.num;
  86. if (typeof options.maxDistance === "number")
  87. this.maxDistance = options.maxDistance;
  88. if (options.query instanceof Object)
  89. this.query = options.query;
  90. if (options.spherical)
  91. this.spherical = Boolean(options.spherical);
  92. if (typeof options.distanceMultiplier === "number")
  93. this.distanceMultiplier = options.distanceMultiplier;
  94. if (options.includeLocs) {
  95. if (typeof options.includeLocs !== "string")
  96. throw new Error("code 16607; $geoNear requires that \"includeLocs\" option is a String");
  97. this.includeLocs = new FieldPath(options.includeLocs);
  98. }
  99. if (options.uniqueDocs)
  100. this.uniqueDocs = Boolean(options.uniqueDocs);
  101. };