summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2012-10-29 14:33:34 -0400
committerMathias Stearn <mathias@10gen.com>2012-11-05 13:03:26 -0500
commit509199b32dc34f302e1d188a9b35bf7e3a4bd017 (patch)
tree178139a8931aa333e5369e245349426ffcc457c2 /src/mongo
parentd8384a53036b471099b8d293ac21b7bd4809df33 (diff)
downloadmongo-509199b32dc34f302e1d188a9b35bf7e3a4bd017.tar.gz
SERVER-7491: Correctly generate projections for subfields of _id
This requires special casing due to SERVER-7502
Diffstat (limited to 'src/mongo')
-rwxr-xr-xsrc/mongo/db/pipeline/document_source.cpp15
-rw-r--r--src/mongo/dbtests/documentsourcetests.cpp55
2 files changed, 68 insertions, 2 deletions
diff --git a/src/mongo/db/pipeline/document_source.cpp b/src/mongo/db/pipeline/document_source.cpp
index e1f033192a9..a459ec0ad10 100755
--- a/src/mongo/db/pipeline/document_source.cpp
+++ b/src/mongo/db/pipeline/document_source.cpp
@@ -87,11 +87,16 @@ namespace mongo {
BSONObj DocumentSource::depsToProjection(const set<string>& deps) {
BSONObjBuilder bb;
- if (deps.count("_id") == 0)
- bb.append("_id", 0);
+
+ bool needId = false;
string last;
for (set<string>::const_iterator it(deps.begin()), end(deps.end()); it!=end; ++it) {
+ if (str::startsWith(*it, "_id") && (it->size() == 3 || (*it)[3] == '.')) {
+ // _id and subfields are handled specially due in part to SERVER-7502
+ needId = true;
+ continue;
+ }
if (!last.empty() && str::startsWith(*it, last)) {
// we are including a parent of *it so we don't need to
// include this field explicitly. In fact, due to
@@ -102,6 +107,12 @@ namespace mongo {
last = *it + '.';
bb.append(*it, 1);
}
+
+ if (needId) // we are explicit either way
+ bb.append("_id", 1);
+ else
+ bb.append("_id", 0);
+
return bb.obj();
}
}
diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp
index bd031a53dc0..63eb71be846 100644
--- a/src/mongo/dbtests/documentsourcetests.cpp
+++ b/src/mongo/dbtests/documentsourcetests.cpp
@@ -44,6 +44,59 @@ namespace DocumentSourceTests {
}
};
+ namespace DocumentSourceClass {
+ using mongo::DocumentSource;
+
+ template<size_t ArrayLen>
+ set<string> arrayToSet(const char* (&array) [ArrayLen]) {
+ set<string> out;
+ for (size_t i = 0; i < ArrayLen; i++)
+ out.insert(array[i]);
+ return out;
+ }
+
+ class Deps {
+ public:
+ void run() {
+ {
+ const char* array[] = {"a", "b"}; // basic
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "b" << 1 << "_id" << 0));
+ }
+ {
+ const char* array[] = {"a", "ab"}; // prefixed but not subfield
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "ab" << 1 << "_id" << 0));
+ }
+ {
+ const char* array[] = {"a", "b", "a.b"}; // a.b included by a
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "b" << 1 << "_id" << 0));
+ }
+ {
+ const char* array[] = {"a", "_id"}; // _id now included
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "_id" << 1));
+ }
+ {
+ const char* array[] = {"a", "_id.a"}; // still include whole _id (SERVER-7502)
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "_id" << 1));
+ }
+ {
+ const char* array[] = {"a", "_id", "_id.a"}; // handle both _id and subfield
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("a" << 1 << "_id" << 1));
+ }
+ {
+ const char* array[] = {"a", "_id", "_id_a"}; // _id prefixed but non-subfield
+ BSONObj proj = DocumentSource::depsToProjection(arrayToSet(array));
+ ASSERT_EQUALS(proj, BSON("_id_a" << 1 << "a" << 1 << "_id" << 1));
+ }
+ }
+ };
+ }
+
namespace DocumentSourceCursor {
using mongo::DocumentSourceCursor;
@@ -1690,6 +1743,8 @@ namespace DocumentSourceTests {
All() : Suite( "documentsource" ) {
}
void setupTests() {
+ add<DocumentSourceClass::Deps>();
+
add<DocumentSourceCursor::Create>();
add<DocumentSourceCursor::Iterate>();
add<DocumentSourceCursor::Dispose>();