You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
7.4 KiB
232 lines
7.4 KiB
4 years ago
|
'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;
|
||
|
}
|
||
|
|
||
|
if (cursorState.session) {
|
||
|
commandOptions.session = cursorState.session;
|
||
|
}
|
||
|
|
||
|
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;
|