[SERVER-12335] indexKey $meta projection not populating fields Created: 11/Jan/14  Updated: 28/Nov/19  Resolved: 28/Nov/19

Status: Closed
Project: Core Server
Component/s: Diagnostics, Querying
Affects Version/s: None
Fix Version/s: 4.3.3

Type: Bug Priority: Minor - P4
Reporter: Andrew Emil (Inactive) Assignee: Anton Korshunov
Resolution: Done Votes: 0
Labels: 26qa, query-44-grooming
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: Text File indexkey_metaprojection.patch    
Issue Links:
Duplicate
is duplicated by SERVER-43168 Ensure "indexKey" option to $meta wor... Closed
Related
is related to SERVER-17929 Add full query support for $meta valu... Backlog
Backwards Compatibility: Fully Compatible
Operating System: ALL
Sprint: Query 2019-12-02
Participants:

 Description   

The indexKey meta projection does not seem to be filling in fields, even when an index seems to be being used.

> db.test.ensureIndex({a:1})
> db.test.insert({a:1})
> db.test.find({a:1}, {b: {$meta: "indexKey"}})
{  }
> db.test.find({a:1}, {b: {$meta: "indexKey"}}).explain()
{
        "cursor" : "BtreeCursor a_1",
        "isMultiKey" : false,
        "n" : 1,
        "nscannedObjects" : 0,
        "nscanned" : 1,
        "nscannedObjectsAllPlans" : 0,
        "nscannedAllPlans" : 1,
        "scanAndOrder" : false,
        "indexOnly" : true,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "a" : [
                        [
                                1,
                                1
                        ]
                ]
        },
        "server" : "Andrew-Emil-MacBook-Pro.local:27017"
}



 Comments   
Comment by Githook User [ 28/Nov/19 ]

Author:

{'email': 'anton.korshunov@mongodb.com', 'name': 'Anton Korshunov', 'username': 'antkorsh'}

Message: SERVER-12335 indexKey $meta projection not populating fields
Branch: master
https://github.com/mongodb/mongo/commit/995798094a170e1bbadb2659cfbe8b750f172b9d

Comment by Max Hirschhorn [ 05/Feb/16 ]

Tess and I spent some time looking at this issue. One problem is that the addKeyMetadata member the IndexScanNode doesn't get set to true if the parsed projection specifies an index key meta projection.

The following patch makes it so that specifying an index key meta projection behaves identically to specifying $returnKey. This seems undesirable as we are effectively ignoring the field that index key meta projection was assigned to and only return the index entry. For example, the following query would return

> db.test.find({a:1}, {b: {$meta: "indexKey"}})
{ "a" : 1 }

rather than {b: {a: 1}}.

diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp
index 54bcc0b..7f449d4 100644
--- a/src/mongo/db/query/planner_access.cpp
+++ b/src/mongo/db/query/planner_access.cpp
@@ -208,6 +208,9 @@ QuerySolutionNode* QueryPlannerAccess::makeLeafNode(
         isn->bounds.fields.resize(index.keyPattern.nFields());
         isn->maxScan = query.getParsed().getMaxScan();
         isn->addKeyMetadata = query.getParsed().returnKey();
+        if (query.getProj() && query.getProj()->wantIndexKey()) {
+            isn->addKeyMetadata = true;
+        }
 
         // Get the ixtag->pos-th element of the index key pattern.
         // TODO: cache this instead/with ixtag->pos?
@@ -1238,6 +1241,9 @@ QuerySolutionNode* QueryPlannerAccess::scanWholeIndex(const IndexEntry& index,
     isn->indexIsMultiKey = index.multikey;
     isn->maxScan = query.getParsed().getMaxScan();
     isn->addKeyMetadata = query.getParsed().returnKey();
+    if (query.getProj() && query.getProj()->wantIndexKey()) {
+        isn->addKeyMetadata = true;
+    }
 
     IndexBoundsBuilder::allValuesBounds(index.keyPattern, &isn->bounds);
 
@@ -1375,6 +1381,10 @@ QuerySolutionNode* QueryPlannerAccess::makeIndexScan(const IndexEntry& index,
     isn->direction = 1;
     isn->maxScan = query.getParsed().getMaxScan();
     isn->addKeyMetadata = query.getParsed().returnKey();
+    if (query.getProj() && query.getProj()->wantIndexKey()) {
+        isn->addKeyMetadata = true;
+    }
+
     isn->bounds.isSimpleRange = true;
     isn->bounds.startKey = startKey;
     isn->bounds.endKey = endKey;

We also need the ProjectionExec code to be able to distinguish between $returnKey and {$meta: 'indexKey' in order to apply a FETCH stage if the projection specification includes fields other than those from the index key. With the indexkey_metaprojection.patch applied, I get the following the behavior when using an indexKey meta-projection.

> db.mycoll.drop();
> db.mycoll.insert({a: 1, c: 1});
> db.mycoll.createIndex({a: 1});
> db.mycoll.find({a: 1}, {_id: 0, a: 0, b: {$meta: "indexKey"}});
{ "c" : 1, "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {_id: 0, a: 1, b: {$meta: "indexKey"}});
{ "a" : 1, "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {_id: 0, c: 1, b: {$meta: "indexKey"}});
{ "c" : 1, "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {_id: 0, c: 0, b: {$meta: "indexKey"}});
{ "a" : 1, "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {_id: 0, b: {$meta: "indexKey"}});
{ "a" : 1, "c" : 1, "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {_id: 1, b: {$meta: "indexKey"}});
{ "_id" : ObjectId("56b4f4b9268d1a261a80c6c0"), "b" : { "a" : 1 } }
> db.mycoll.find({a: 1}, {b: {$meta: "indexKey"}});
{ "_id" : ObjectId("56b4f4b9268d1a261a80c6c0"), "a" : 1, "c" : 1, "b" : { "a" : 1 } }

Unassigning this ticket from myself until cleanup of ProjectionExec happens as part of SERVER-20795.

Generated at Thu Feb 08 03:28:15 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.