4

Given the following layout in a collection...

{
  vehicle_id: 1
  ,// bunch of properties I don't want
  ,vehicle: {
    mfg_year: 1928
    ,mfg_make: "Ford"
    ,mfg_model: "Model A"
    ,mfg_trim: "T-Bucket"
    ,// bunch of properties I don't want
    ,images: [
      {url:'...',...}
      ,...
    ]
  }
}

How would I return a result with only the above fields, and only the first result under images? I don't mind if the results are in one flattened object, with only the images being a nested object.

I've looked into the Aggregation Framework, which doesn't seem to match what I am looking for. I know I could do a map/reduce on the results set, or do a group on the listing_id, am just hoping to have a simpler query structure without needing to resort to group, or reduce.

If this isn't possible currently via the aggregation framework, a working group or map-reduce would be an acceptable answer.


EDIT: There are about 50+ properties that I don't want in the final result.. with the $slice directive, it seems I can't just specify the fields I want.

2
  • group / map-reduce queries shouldn't be used for 'real time' queries Commented Nov 19, 2012 at 17:47
  • @alexjamesbrown I understand that, which is why I'm hoping for a more optimized query... $slice leads in the right direction though. Commented Nov 19, 2012 at 18:06

2 Answers 2

8

How about:

db.vehicles.find({"vehicle_id":1}, {images:{$slice: 1}})

Source: http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements

Example

db.vehicles.insert({"vehicle_id": 1, "mfg_year": "1928", "mfg_make": "Ford", "mfg_model": "Model A", "images": [{"url":"www.a.com"}, {"url":"www.b.com"}, {"url":"www.c.com"}]})

db.vehicles.insert({"vehicle_id": 2, "mfg_year": "1999", "mfg_make": "BMW", "mfg_model": "Model B", "images": [{"url":"www.a.com"}, {"url":"www.b.com"}, {"url":"www.c.com"}]})

db.vehicles.insert({"vehicle_id": 3, "mfg_year": "1998", "mfg_make": "FMerc", "mfg_model": "Model C", "images": [{"url":"www.a.com"}, {"url":"www.b.com"}, {"url":"www.c.com"}]})


//now the query
db.vehicles.find({"vehicle_id":1}, {images:{$slice: 1}})

Output:

{
        "vehicle_id" : 1,
        "mfg_year" : "1928",
        "mfg_make" : "Ford",
        "mfg_model" : "Model A",
        "images" : [
                {
                        "url" : "www.a.com"
                }
        ]
}

EDIT

You can specify just the fields you want to return like this:

db.vehicles.find({"vehicle_id":1}, {"mfg_make":1, images:{$slice: 1}})

So, in this instance, only the mfg_make and images is returned.

Another....

db.vehicles.find({"vehicle_id":1}, {"mfg_make":1, "some_other_field":1, images:{$slice: 1}})

If this were a RDBMS, this query is equivalent to:

SELECT mfg_make, some_other_field FROM tblVehicles WHERE vehicle_id = 1
Sign up to request clarification or add additional context in comments.

6 Comments

Should have been more clear... there are about 50 other properties that I don't want in the results... is there a way to only get the above properties, without 50+ false entries for the field selectors?
'in the results' - is that in the array of images, or in the main body of 'vehicle'?
edited answer to cover how to choose what fields to return. It sounds like you have more fields to exclude, than to include, so it will be easier to list the ones to INCLUDE rather than EXCLUDE
Thank you... for some reason if there's only one field beyond the slice specified, it returned all fields.
@Tracker1 The one field beyond is probably _id, which is projected unless explicitly excluded; however the above doesn't quite work if you only specify the slice; what you'd need (today) is {images:{$slice:1}, images:1, _id:0}
|
0

With aggregation framework you have the operators $project and $first (available in MongoDB version 4.4 and above) to get the desired result:

db.collection.aggregate([
    { '$project': {
        'vehicle_id': 1,
        'vehicle': {
            'mfg_year': '$vehicle.mfg_year',
            'mfg_make': '$vehicle.mfg_make',
            'mfg_model': '$vehicle.mfg_model',
            'mfg_trim': '$vehicle.mfg_trim',
            'images': { '$first': '$vehicle.images' }
        }
    } }   
])

or with $arrayElemAt

db.collection.aggregate([
    { '$project': {
        'vehicle_id': 1,
        'vehicle': {
            'mfg_year': '$vehicle.mfg_year',
            'mfg_make': '$vehicle.mfg_make',
            'mfg_model': '$vehicle.mfg_model',
            'mfg_trim': '$vehicle.mfg_trim',
            'images': { '$arrayElemAt': ['$vehicle.images', 0] }
        }
    } }   
])

or with $slice

db.collection.aggregate([
    { '$project': {
        'vehicle_id': 1,
        'vehicle': {
            'mfg_year': '$vehicle.mfg_year',
            'mfg_make': '$vehicle.mfg_make',
            'mfg_model': '$vehicle.mfg_model',
            'mfg_trim': '$vehicle.mfg_trim',
            'images': { '$slice': ['$vehicle.images', 1] }
        }
    } }   
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.