Changed UpdateStage to return the prior or newly-updated version of a document if request. also changed DeleteStage to return the deleted document if requested. Added explain support to the findAndModify command.
354 lines
11 KiB
JavaScript
354 lines
11 KiB
JavaScript
/**
|
|
* Test that projection with a positional operator works with findAndModify
|
|
* when remove=true or new=false, but not when new=true.
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
var collName = 'find_and_modify_server6865';
|
|
var t = db.getCollection(collName);
|
|
t.drop();
|
|
|
|
/**
|
|
* Asserts that the specified query and projection returns the expected
|
|
* result, using both the find() operation and the findAndModify command.
|
|
*
|
|
* insert -- document to insert after dropping collection t
|
|
* cmdObj -- arguments to the findAndModify command
|
|
*
|
|
* expected -- the document 'value' expected to be returned after the
|
|
* projection is applied
|
|
*/
|
|
function testFAMWorked(insert, cmdObj, expected) {
|
|
t.drop();
|
|
t.insert(insert);
|
|
|
|
var res;
|
|
|
|
if (!cmdObj['new']) {
|
|
// Test that the find operation returns the expected result.
|
|
res = t.findOne(cmdObj['query'], cmdObj['fields']);
|
|
assert.eq(res, expected, 'positional projection failed for find');
|
|
}
|
|
|
|
// Test that the findAndModify command returns the expected result.
|
|
res = t.runCommand('findAndModify', cmdObj);
|
|
assert.commandWorked(res, 'findAndModify command failed');
|
|
assert.eq(res.value, expected, 'positional projection failed for findAndModify');
|
|
|
|
if (cmdObj['new']) {
|
|
// Test that the find operation returns the expected result.
|
|
res = t.findOne(cmdObj['query'], cmdObj['fields']);
|
|
assert.eq(res, expected, 'positional projection failed for find');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Asserts that the specified findAndModify command returns an error.
|
|
*/
|
|
function testFAMFailed(insert, cmdObj) {
|
|
t.drop();
|
|
t.insert(insert);
|
|
|
|
var res = t.runCommand('findAndModify', cmdObj);
|
|
assert.commandFailed(res, 'findAndModify command unexpectedly succeeded');
|
|
}
|
|
|
|
//
|
|
// Delete operations
|
|
//
|
|
|
|
// Simple query that uses an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3},
|
|
{query: {_id: 42}, fields: {_id: 0, b: 1}, remove: true},
|
|
{b: 3}
|
|
);
|
|
|
|
// Simple query that uses an exclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3, c: 4},
|
|
{query: {_id: 42}, fields: {a: 0, b: 0}, remove: true},
|
|
{_id: 42, c: 4}
|
|
);
|
|
|
|
// Simple query that uses $elemMatch in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{query: {_id: 42}, fields: {b: {$elemMatch: {value: 2}}}, remove: true},
|
|
{_id: 42, b: [{name: 'second', value: 2}]}
|
|
);
|
|
|
|
// Query on an array of values while using a positional projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2]},
|
|
{query: {a: 2}, fields: {'a.$': 1}, remove: true},
|
|
{_id: 42, a: [2]}
|
|
);
|
|
|
|
// Query on an array of objects while using a positional projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{query: {_id: 42, 'b.name': 'third'}, fields: {'b.$': 1}, remove: true},
|
|
{_id: 42, b: [{name: 'third', value: 3}]}
|
|
);
|
|
|
|
// Query on an array of objects while using a position projection.
|
|
// Verifies that the projection {'b.$.value': 1} is treated the
|
|
// same as {'b.$': 1}.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{query: {_id: 42, 'b.name': 'third'}, fields: {'b.$.value': 1}, remove: true},
|
|
{_id: 42, b: [{name: 'third', value: 3}]}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: 5, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, a: 5},
|
|
remove: true
|
|
},
|
|
{a: 5}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using the positional
|
|
// operator in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, 'b.$': 1},
|
|
remove: true
|
|
},
|
|
{b: [{name: 'john', value: 1}]}
|
|
);
|
|
|
|
//
|
|
// Update operations with new=false
|
|
//
|
|
|
|
// Simple query that uses an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3},
|
|
{query: {_id: 42}, fields: {_id: 0, b: 1}, update: {$inc: {b: 1}}, new: false},
|
|
{b: 3}
|
|
);
|
|
|
|
// Simple query that uses an exclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3, c: 4},
|
|
{query: {_id: 42}, fields: {a: 0, b: 0}, update: {$set: {c: 5}}, new: false},
|
|
{_id: 42, c: 4}
|
|
);
|
|
|
|
// Simple query that uses $elemMatch in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{
|
|
query: {_id: 42},
|
|
fields: {b: {$elemMatch: {value: 2}}},
|
|
update: {$set: {name: '2nd'}},
|
|
new: false
|
|
},
|
|
{_id: 42, b: [{name: 'second', value: 2}]}
|
|
);
|
|
|
|
// Query on an array of values while using a positional projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2]},
|
|
{query: {a: 2}, fields: {'a.$': 1}, update: {$set: {'b.kind': 'xyz'}}, new: false},
|
|
{_id: 42, a: [2]}
|
|
);
|
|
|
|
// Query on an array of objects while using a positional projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{
|
|
query: {_id: 42, 'b.name': 'third'},
|
|
fields: {'b.$': 1},
|
|
update: {$set: {'b.$.kind': 'xyz'}},
|
|
new: false
|
|
},
|
|
{_id: 42, b: [{name: 'third', value: 3}]}
|
|
);
|
|
|
|
// Query on an array of objects while using $elemMatch in the projection,
|
|
// where the matched array element is modified.
|
|
testFAMWorked(
|
|
{_id: 1, a: [{x: 1, y: 1}, {x: 1, y: 2}]},
|
|
{
|
|
query: {_id: 1},
|
|
fields: {a: {$elemMatch: {x: 1}}},
|
|
update: {$pop: {a: -1}},
|
|
new: false
|
|
},
|
|
{_id: 1, a: [{x: 1, y: 1}]}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: 5, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, a: 5},
|
|
update: {$inc: {a: 6}},
|
|
new: false
|
|
},
|
|
{a: 5}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using the positional
|
|
// operator in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, 'b.$': 1},
|
|
update: {$set: {name: 'james'}},
|
|
new: false
|
|
},
|
|
{b: [{name: 'john', value: 1}]}
|
|
);
|
|
|
|
//
|
|
// Update operations with new=true
|
|
//
|
|
|
|
// Simple query that uses an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3},
|
|
{query: {_id: 42}, fields: {_id: 0, b: 1}, update: {$inc: {b: 1}}, new: true},
|
|
{b: 4}
|
|
);
|
|
|
|
// Simple query that uses an exclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: [1, 2], b: 3, c: 4},
|
|
{query: {_id: 42}, fields: {a: 0, b: 0}, update: {$set: {c: 5}}, new: true},
|
|
{_id: 42, c: 5}
|
|
);
|
|
|
|
// Simple query that uses $elemMatch in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{
|
|
query: {_id: 42},
|
|
fields: {b: {$elemMatch: {value: 2}}},
|
|
update: {$set: {'b.1.name': '2nd'}},
|
|
new: true
|
|
},
|
|
{_id: 42, b: [{name: '2nd', value: 2}]}
|
|
);
|
|
|
|
// Query on an array of values while using a positional projection.
|
|
testFAMFailed(
|
|
{_id: 42, a: [1, 2]},
|
|
{query: {a: 2}, fields: {'a.$': 1}, update: {$set: {'b.kind': 'xyz'}}, new: true}
|
|
);
|
|
|
|
// Query on an array of objects while using a positional projection.
|
|
testFAMFailed(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{
|
|
query: {_id: 42, 'b.name': 'third'},
|
|
fields: {'b.$': 1},
|
|
update: {$set: {'b.$.kind': 'xyz'}},
|
|
new: true
|
|
}
|
|
);
|
|
|
|
// Query on an array of objects while using $elemMatch in the projection.
|
|
testFAMWorked(
|
|
{_id: 42, b: [{name: 'first', value: 1},
|
|
{name: 'second', value: 2},
|
|
{name: 'third', value: 3}]
|
|
},
|
|
{
|
|
query: {_id: 42},
|
|
fields: {b: {$elemMatch: {value: 2}}, c: 1},
|
|
update: {$set: {c: 'xyz'}},
|
|
new: true
|
|
},
|
|
{_id: 42, b: [{name: 'second', value: 2}], c: 'xyz'}
|
|
);
|
|
|
|
// Query on an array of objects while using $elemMatch in the projection,
|
|
// where the matched array element is modified.
|
|
testFAMWorked(
|
|
{_id: 1, a: [{x: 1, y: 1}, {x: 1, y: 2}]},
|
|
{
|
|
query: {_id: 1},
|
|
fields: {a: {$elemMatch: {x: 1}}},
|
|
update: {$pop: {a: -1}},
|
|
new: true
|
|
},
|
|
{_id: 1, a: [{x: 1, y: 2}]}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using an inclusion projection.
|
|
testFAMWorked(
|
|
{_id: 42, a: 5, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, a: 5},
|
|
update: {$inc: {a: 6}},
|
|
new: true
|
|
},
|
|
{a: 11}
|
|
);
|
|
|
|
// Query on an array of objects using $elemMatch while using the positional
|
|
// operator in the projection.
|
|
testFAMFailed(
|
|
{_id: 42, b: [{name: 'john', value: 1},
|
|
{name: 'jess', value: 2},
|
|
{name: 'jeff', value: 3}]
|
|
},
|
|
{
|
|
query: {b: {$elemMatch: {name: 'john', value: {$lt: 2}}}},
|
|
fields: {_id: 0, 'b.$': 1},
|
|
update: {$set: {name: 'james'}},
|
|
new: true
|
|
}
|
|
);
|
|
|
|
})();
|