summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2014-02-06 11:52:13 -0500
committerBenety Goh <benety@mongodb.com>2014-02-07 13:16:44 -0500
commite01492875083bf30bba35b38a8a0301e66c422df (patch)
tree4f2c1e31f96ce38c9f07fdd148db6aaa8e9abe16 /src/mongo
parent795353195c696a95a6f18a4deb38dfb5ad588ab9 (diff)
downloadmongo-e01492875083bf30bba35b38a8a0301e66c422df.tar.gz
SERVER-12129 meta projection operator should overwrite fields
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/exec/projection_exec.cpp8
-rw-r--r--src/mongo/db/exec/projection_exec.h4
-rw-r--r--src/mongo/db/exec/projection_exec_test.cpp30
3 files changed, 40 insertions, 2 deletions
diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp
index 05a33a24002..15a224cbe72 100644
--- a/src/mongo/db/exec/projection_exec.cpp
+++ b/src/mongo/db/exec/projection_exec.cpp
@@ -479,6 +479,14 @@ namespace mongo {
const MatchDetails* details,
const ArrayOpType arrayOpType) const {
+
+ // Skip if the field name matches a computed $meta field.
+ // $meta projection fields can exist at the top level of
+ // the result document and the field names cannot be dotted.
+ if (_meta.find(elt.fieldName()) != _meta.end()) {
+ return Status::OK();
+ }
+
FieldMap::const_iterator field = _fields.find(elt.fieldName());
if (field == _fields.end()) {
if (_include) {
diff --git a/src/mongo/db/exec/projection_exec.h b/src/mongo/db/exec/projection_exec.h
index eefeb5e8c9a..796e8c62283 100644
--- a/src/mongo/db/exec/projection_exec.h
+++ b/src/mongo/db/exec/projection_exec.h
@@ -178,10 +178,10 @@ namespace mongo {
ArrayOpType _arrayOpType;
- // Is there an elemMatch or positional operator?
+ // Is there an slice, elemMatch or meta operator?
bool _hasNonSimple;
- // Is there a projection over a dotted field?
+ // Is there a projection over a dotted field or a $ positional operator?
bool _hasDottedField;
// The full query expression. Used when we need MatchDetails.
diff --git a/src/mongo/db/exec/projection_exec_test.cpp b/src/mongo/db/exec/projection_exec_test.cpp
index 6267f32fabe..59af37dd6d4 100644
--- a/src/mongo/db/exec/projection_exec_test.cpp
+++ b/src/mongo/db/exec/projection_exec_test.cpp
@@ -34,6 +34,7 @@
#include <memory>
#include "mongo/db/json.h"
+#include "mongo/db/exec/working_set_computed_data.h"
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/unittest/unittest.h"
@@ -64,12 +65,14 @@ namespace {
* specStr - projection specification
* queryStr - query
* objStr - object to run projection on
+ * data - computed data. Owned by working set member created in this function if not null.
* expectedStatusOK - expected status of transformation
* expectedObjStr - expected object after successful projection.
* Ignored if expectedStatusOK is false.
*/
void testTransform(const char* specStr, const char* queryStr, const char* objStr,
+ WorkingSetComputedData* data,
bool expectedStatusOK, const char* expectedObjStr) {
// Create projection exec object.
BSONObj spec = fromjson(specStr);
@@ -81,6 +84,9 @@ namespace {
WorkingSetMember wsm;
wsm.state = WorkingSetMember::OWNED_OBJ;
wsm.obj = fromjson(objStr);
+ if (data) {
+ wsm.addComputed(data);
+ }
// Transform object
Status status = exec.transform(&wsm);
@@ -125,6 +131,14 @@ namespace {
}
}
+ /**
+ * testTransform without computed data argument.
+ */
+ void testTransform(const char* specStr, const char* queryStr, const char* objStr,
+ bool expectedStatusOK, const char* expectedObjStr) {
+ testTransform(specStr, queryStr, objStr, NULL, expectedStatusOK, expectedObjStr);
+ }
+
//
// position $
//
@@ -186,4 +200,20 @@ namespace {
testTransform("{a: {$slice: [10, 10]}}", "{}", "{a: [4, 6, 8]}", true, "{a: []}");
}
+ //
+ // $meta
+ // $meta projections add computed values to the projected object.
+ //
+
+ TEST(ProjectionExecTest, TransformMetaTextScore) {
+ // Query {} is ignored.
+ testTransform("{b: {$meta: 'textScore'}}", "{}", "{a: 'hello'}",
+ new mongo::TextScoreComputedData(100),
+ true, "{a: 'hello', b: 100}");
+ // Projected meta field should overwrite existing field.
+ testTransform("{b: {$meta: 'textScore'}}", "{}", "{a: 'hello', b: -1}",
+ new mongo::TextScoreComputedData(100),
+ true, "{a: 'hello', b: 100}");
+ }
+
} // namespace