Question

I have a collection like such:

db.collection1 = 
{
    "_id" : ObjectId(),
    "array" : [
        {
            "userid" : ObjectId(),
            "subfield1" : string,
            "subfield2" : number,
            "subfield3" : number,
            "subfield4" : Date
        },...
    ],
    "field1" : date,
    "field2" : date,
    "field3" : date,
    "field4" : date,
    "field5" : number,
    "field6" : [],
    "field7" : String,
    "field8" : {}
},...

Now, I am using a find query on the basis of the userid field inside the array, that is somewhat like this:

db.collection1.find({array:{"$elemMatch":{userid:uId}})

But what I also want is just before retrieving a record it should fetch that particular array element also and append it as a property of the returned object.

My 2nd query for this would be:

db.collection1.find({'array.userId':uId},{'array.$':1})

But I want the result of this 2nd query to be appended as a propery of the object returned in first query

I hope I am clear.....

OK

My projection would be something like this:

{array.subfield2:0,array.subfield3:0,field2:0,field6:0,field7:0}

So this is what I want as a result...suppposing there are 3 users and the third user matches the userId that I am passing. The retrieved document should look like this.

{
 _id: ObjectId(),
 array:[
 {
  userid:ObjectId(1),
  subfield1:string,
  subfield4:Date
 },
 {
  userid:ObjectId(2),
  subfield1:string,
  subfield4:Date
 },
 {
  userid:ObjectId(3),
  subfield1:string,
  subfield4:Date
 }],
 "field1" : date,
 "field3" : date,
 "field4" : date,
 "field5" : number,
 "field8" : {},
 DynamicField://This is the userobj of the 3rd usr which matches. Whole & intact 
 {
   "userid" : ObjectId(3),
   "subfield1" : string,
   "subfield2" : number,
   "subfield3" : number,
   "subfield4" : Date
 }
}
Was it helpful?

Solution

I think a lot of people have been confused by your terminology of "appending", but if I read between the lines of what you are saying you seem to want the "whole document" to be returned but only including the "matched element" of the array.

So like all general "field selection" techniques, you have to be very specific with MongoDB and include all of the field names in your projection:

db.collection1.find(
    { "array.userid": uId },   // Don't need elemMatch with one field
    {
        "array.$": 1,
        "field1": 1,
        "field2": 1,
        "field3": 1,
        "field4": 1,
        "field5": 1,
        "field6": 1,
        "field7": 1,
        "field8": 1,
    }
)

The _id is always included unless explicitly excluded and you cannot "mix" other includes/excludes in here, not that it would make much sense since you need the matched position within the array.

Edit: I have no idea why you would want to do this, to me the above form is much better:

 db.collection1.aggregate([
     // Filter the matching document, as you do not want to do the rest of the
     // steps over the whole collection
     { "$match": {
         "array.userid": uId,   // Don't need elemMatch with one field
     }},

     // Store the original document, and a copy of the array
     { "$project": {
         "array": 1,
         "field1": 1,
         "field3": 1,
         "field4": 1,
         "field5": 1,
         "field8": 1,
         "dynamicField": "$array"
     }},

     // Unwind the array
     { "$unwind": "$dynamicField" },

     // Just match the field you want
     { "$match": { "dynamicField.userid": uId } },

     // Play with the other array now
     { "$unwind": "$array" },

     // Change the projection
     { "$project": {
         "array.userId": "$array.userId",
         "array.subfield1": "$array.subfield1", 
         "array.subfield4": "$array.subfield4", 
         "field1": 1,
         "field2": 1,
         "field3": 1,
         "field4": 1,
         "field5": 1,
         "field6": 1,
         "field7": 1,
         "field8": 1,
         "dynamicField": 1
     }},

     // Group back the array
     { "$group": {
         "_id": "$_id",
         "array": { "$push": "$array" },
         "field1": { "$first": "$field1" },
         "field3": { "$first": "$field3" },
         "field4": { "$first": "$field4" },
         "field5": { "$first": "$field5" },
         "field8": { "$first": "$field8" },
         "dynamicField": { "$first": "$dynamicField" }
     }}

 ])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top