How do I return a field under a different key?

Hi, so I have data as such:

{
  _id: someID,
  field1: [data],
  field2: [data]
  field3: {
    field3_1: data,
    ...
  }
}

Is it possible during a query to to return field1 and field2 under field3? I tried the following but got a path collision error:

db.findOne({ _id: someID }, { fields: { "field3.field1": "$field1", "field3.field2": "$field2", field3: 1 }})

The syntax may be a little different as I’m using Mongo with Meteor. Here we need to specify the fields key explicitly.

Note that field3 does not contain the keys field1 or field2.

Appreciate any help, thank you!

Hi @Ajay_Pillay

Have you tried the following:

db.findOne({ _id: someID }, { fields: { "field3" : {"field1": "$field1", "field2": "$field2"}}})

Or maybe just :

db.findOne({ _id: someID }, { fields: { "field3.field1": "$field1", "field3.field2": "$field2"}})

Eventually I believe the error is as you specified field3 twice which I am not sure why…

Thanks
Pavel

Hi,

Eventually I believe the error is as you specified field3 twice which I am not sure why…

I didn’t specify field3 twice anywhere. If you were referring to the JSON data, it’s field3_1, sorry if that wasn’t clear.

Both of the suggestions return the following:

{
  _id: "someID"
  field3: {
    field1: [data],
    field2: [data]
  }
}

But all the other data in field3 is not returned. Just to make it clearer, so as per my OP I have the following data (copied verbatim):

{
  _id: someID,
  field1: [data],
  field2: [data]
  field3: {
    field3_1: data,
    ...
  }
}

What I want to do is query the whole of field3 but also include field1 and field2 as sub-fields of field3, even though the data stored does not have field1 and field2 as sub-fields for field3. I’m trying to avoid to have to do this as post-processing where I copy/move the data into field3.field1 and field3.field2. So here’s how the final query should look like:

{
  _id: someID,
  field3: {
    field1: [data],
    field2: [data],
    field3_1: data,
    ...
  }
}

To give some context as to why I want to do this, it’s part of building a Graphql API, and the schema would require that field1 and field2 are sub-fields of field3. I’m trying to avoid having to do unnecessary post-processing to get them as sub-fields of field3. If I can accomplish this with a simple query call that would be great.

But I think this might need an aggregation approach instead?

Thanks!

Hi @Ajay_Pillay,

You can do this using an Aggregation Pipeline as follows:

// setup
db.foo.drop();
db.foo.insert({
  _id: 1,
  field1: "a",
  field2: "b",
  field3: {
    field3_1: "c"
  }
});
db.foo.find();
/*
{ 
    "_id" : 1.0, 
    "field1" : "a", 
    "field2" : "b", 
    "field3" : {
        "field3_1" : "c"
    }
}
*/

Assuming the structure above matches your sample structure, to achieve the result you described you can first $match to filter the results, use $addFields to append to the field3 object and then use a $project to remove field1 and field2 from the top level of the resulting document:

db.foo.aggregate([
{ $match: { _id: 1 } },
{ $addFields: { 
    "field3.field1": "$field1", 
    "field3.field2": "$field2"
}},
{ $project: { field1: 0, field2: 0 } }
])
/*
{ 
    "_id" : 1.0, 
    "field3" : {
        "field3_1" : "c", 
        "field1" : "a", 
        "field2" : "b"
    }
}
*/
2 Likes

Thank you very much, this works as intended!

The only change I needed to make is $project: { _id: 0, field3: 1 } as I only need to return field3.

@Ajay_Pillay

Just FYI, the solution can be simplified slightly to just use a single $project along with a $mergeObjects as follows:

db.foo.aggregate([
{ $match: { _id: 1 } },
{ $project: { 
    _id: 0,
    field3: { $mergeObjects: [ "$field3", 
        { field1: "$field1", field2: "$field2" }
    ]}
}}
])
2 Likes

Oh, that’s great, I shall do this instead. Thank you again!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.