123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- 'use strict';
- const Query = require('../connection/commands').Query;
- const MongoError = require('../error').MongoError;
- const getReadPreference = require('./shared').getReadPreference;
- const collectionNamespace = require('./shared').collectionNamespace;
- const isSharded = require('./shared').isSharded;
- const maxWireVersion = require('../utils').maxWireVersion;
- const applyCommonQueryOptions = require('./shared').applyCommonQueryOptions;
- const command = require('./command');
- function query(server, ns, cmd, cursorState, options, callback) {
- options = options || {};
- if (cursorState.cursorId != null) {
- return callback();
- }
- if (cmd == null) {
- return callback(new MongoError(`command ${JSON.stringify(cmd)} does not return a cursor`));
- }
- if (maxWireVersion(server) < 4) {
- const query = prepareLegacyFindQuery(server, ns, cmd, cursorState, options);
- const queryOptions = applyCommonQueryOptions({}, cursorState);
- if (typeof query.documentsReturnedIn === 'string') {
- queryOptions.documentsReturnedIn = query.documentsReturnedIn;
- }
- server.s.pool.write(query, queryOptions, callback);
- return;
- }
- const readPreference = getReadPreference(cmd, options);
- const findCmd = prepareFindCommand(server, ns, cmd, cursorState, options);
- // NOTE: This actually modifies the passed in cmd, and our code _depends_ on this
- // side-effect. Change this ASAP
- cmd.virtual = false;
- const commandOptions = Object.assign(
- {
- documentsReturnedIn: 'firstBatch',
- numberToReturn: 1,
- slaveOk: readPreference.slaveOk()
- },
- options
- );
- if (cmd.readPreference) commandOptions.readPreference = readPreference;
- command(server, ns, findCmd, commandOptions, callback);
- }
- function prepareFindCommand(server, ns, cmd, cursorState) {
- cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
- let findCmd = {
- find: collectionNamespace(ns)
- };
- if (cmd.query) {
- if (cmd.query['$query']) {
- findCmd.filter = cmd.query['$query'];
- } else {
- findCmd.filter = cmd.query;
- }
- }
- let sortValue = cmd.sort;
- if (Array.isArray(sortValue)) {
- const sortObject = {};
- if (sortValue.length > 0 && !Array.isArray(sortValue[0])) {
- let sortDirection = sortValue[1];
- if (sortDirection === 'asc') {
- sortDirection = 1;
- } else if (sortDirection === 'desc') {
- sortDirection = -1;
- }
- sortObject[sortValue[0]] = sortDirection;
- } else {
- for (let i = 0; i < sortValue.length; i++) {
- let sortDirection = sortValue[i][1];
- if (sortDirection === 'asc') {
- sortDirection = 1;
- } else if (sortDirection === 'desc') {
- sortDirection = -1;
- }
- sortObject[sortValue[i][0]] = sortDirection;
- }
- }
- sortValue = sortObject;
- }
- if (cmd.sort) findCmd.sort = sortValue;
- if (cmd.fields) findCmd.projection = cmd.fields;
- if (cmd.hint) findCmd.hint = cmd.hint;
- if (cmd.skip) findCmd.skip = cmd.skip;
- if (cmd.limit) findCmd.limit = cmd.limit;
- if (cmd.limit < 0) {
- findCmd.limit = Math.abs(cmd.limit);
- findCmd.singleBatch = true;
- }
- if (typeof cmd.batchSize === 'number') {
- if (cmd.batchSize < 0) {
- if (cmd.limit !== 0 && Math.abs(cmd.batchSize) < Math.abs(cmd.limit)) {
- findCmd.limit = Math.abs(cmd.batchSize);
- }
- findCmd.singleBatch = true;
- }
- findCmd.batchSize = Math.abs(cmd.batchSize);
- }
- if (cmd.comment) findCmd.comment = cmd.comment;
- if (cmd.maxScan) findCmd.maxScan = cmd.maxScan;
- if (cmd.maxTimeMS) findCmd.maxTimeMS = cmd.maxTimeMS;
- if (cmd.min) findCmd.min = cmd.min;
- if (cmd.max) findCmd.max = cmd.max;
- findCmd.returnKey = cmd.returnKey ? cmd.returnKey : false;
- findCmd.showRecordId = cmd.showDiskLoc ? cmd.showDiskLoc : false;
- if (cmd.snapshot) findCmd.snapshot = cmd.snapshot;
- if (cmd.tailable) findCmd.tailable = cmd.tailable;
- if (cmd.oplogReplay) findCmd.oplogReplay = cmd.oplogReplay;
- if (cmd.noCursorTimeout) findCmd.noCursorTimeout = cmd.noCursorTimeout;
- if (cmd.awaitData) findCmd.awaitData = cmd.awaitData;
- if (cmd.awaitdata) findCmd.awaitData = cmd.awaitdata;
- if (cmd.partial) findCmd.partial = cmd.partial;
- if (cmd.collation) findCmd.collation = cmd.collation;
- if (cmd.readConcern) findCmd.readConcern = cmd.readConcern;
- // If we have explain, we need to rewrite the find command
- // to wrap it in the explain command
- if (cmd.explain) {
- findCmd = {
- explain: findCmd
- };
- }
- return findCmd;
- }
- function prepareLegacyFindQuery(server, ns, cmd, cursorState, options) {
- options = options || {};
- const bson = server.s.bson;
- const readPreference = getReadPreference(cmd, options);
- cursorState.batchSize = cmd.batchSize || cursorState.batchSize;
- let numberToReturn = 0;
- if (
- cursorState.limit < 0 ||
- (cursorState.limit !== 0 && cursorState.limit < cursorState.batchSize) ||
- (cursorState.limit > 0 && cursorState.batchSize === 0)
- ) {
- numberToReturn = cursorState.limit;
- } else {
- numberToReturn = cursorState.batchSize;
- }
- const numberToSkip = cursorState.skip || 0;
- const findCmd = {};
- if (isSharded(server) && readPreference) {
- findCmd['$readPreference'] = readPreference.toJSON();
- }
- if (cmd.sort) findCmd['$orderby'] = cmd.sort;
- if (cmd.hint) findCmd['$hint'] = cmd.hint;
- if (cmd.snapshot) findCmd['$snapshot'] = cmd.snapshot;
- if (typeof cmd.returnKey !== 'undefined') findCmd['$returnKey'] = cmd.returnKey;
- if (cmd.maxScan) findCmd['$maxScan'] = cmd.maxScan;
- if (cmd.min) findCmd['$min'] = cmd.min;
- if (cmd.max) findCmd['$max'] = cmd.max;
- if (typeof cmd.showDiskLoc !== 'undefined') findCmd['$showDiskLoc'] = cmd.showDiskLoc;
- if (cmd.comment) findCmd['$comment'] = cmd.comment;
- if (cmd.maxTimeMS) findCmd['$maxTimeMS'] = cmd.maxTimeMS;
- if (cmd.explain) {
- // nToReturn must be 0 (match all) or negative (match N and close cursor)
- // nToReturn > 0 will give explain results equivalent to limit(0)
- numberToReturn = -Math.abs(cmd.limit || 0);
- findCmd['$explain'] = true;
- }
- findCmd['$query'] = cmd.query;
- if (cmd.readConcern && cmd.readConcern.level !== 'local') {
- throw new MongoError(
- `server find command does not support a readConcern level of ${cmd.readConcern.level}`
- );
- }
- if (cmd.readConcern) {
- cmd = Object.assign({}, cmd);
- delete cmd['readConcern'];
- }
- const serializeFunctions =
- typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
- const ignoreUndefined =
- typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
- const query = new Query(bson, ns, findCmd, {
- numberToSkip: numberToSkip,
- numberToReturn: numberToReturn,
- pre32Limit: typeof cmd.limit !== 'undefined' ? cmd.limit : undefined,
- checkKeys: false,
- returnFieldSelector: cmd.fields,
- serializeFunctions: serializeFunctions,
- ignoreUndefined: ignoreUndefined
- });
- if (typeof cmd.tailable === 'boolean') query.tailable = cmd.tailable;
- if (typeof cmd.oplogReplay === 'boolean') query.oplogReplay = cmd.oplogReplay;
- if (typeof cmd.noCursorTimeout === 'boolean') query.noCursorTimeout = cmd.noCursorTimeout;
- if (typeof cmd.awaitData === 'boolean') query.awaitData = cmd.awaitData;
- if (typeof cmd.partial === 'boolean') query.partial = cmd.partial;
- query.slaveOk = readPreference.slaveOk();
- return query;
- }
- module.exports = query;
|