Получение только первого элемента для свойства массива в mongodb

Учитывая следующий макет в коллекции...

{
  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:'...',...}
      ,...
    ]
  }
}

Как мне вернуть результат только с указанными выше полями и только с первым результатом под изображениями? Я не возражаю, если результаты будут в одном плоском объекте, и только изображения будут вложенными объектами.

Я просмотрел структуру агрегации, которая, похоже, не соответствует тому, что я ищу. Я знаю, что мог бы сделать карту/уменьшить для набора результатов или создать группу для listing_id, я просто надеюсь иметь более простую структуру запроса без необходимости прибегать к группе или сокращению.

Если в настоящее время это невозможно с помощью структуры агрегации, приемлемым ответом будет рабочая группа или уменьшение карты.


РЕДАКТИРОВАТЬ: есть около 50+ свойств, которые мне не нужны в конечном результате.. с директивой $slice, похоже, я не могу просто указать нужные поля.


person Tracker1    schedule 19.11.2012    source источник
comment
запросы group/map-reduce не должны использоваться для запросов «в реальном времени»   -  person Alex    schedule 19.11.2012
comment
@alexjamesbrown Я понимаю это, поэтому я надеюсь на более оптимизированный запрос ... Однако $slice ведет в правильном направлении.   -  person Tracker1    schedule 19.11.2012


Ответы (2)


Как насчет:

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

Источник: http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements

Пример

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}})

Выход:

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

ИЗМЕНИТЬ

Вы можете указать только те поля, которые хотите вернуть, следующим образом:

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

Итак, в этом случае возвращаются только mfg_make и images.

Другая....

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

Если бы это была СУБД, этот запрос эквивалентен следующему:

SELECT mfg_make, some_other_field FROM tblVehicles WHERE vehicle_id = 1
person Alex    schedule 19.11.2012
comment
Должно было быть более ясно... есть около 50 других свойств, которые мне не нужны в результатах... есть ли способ получить только вышеуказанные свойства без более 50 ложных записей для селекторов полей? - person Tracker1; 19.11.2012
comment
«в результатах» — это в массиве изображений или в основной части «транспортного средства»? - person Alex; 19.11.2012
comment
отредактированный ответ, чтобы понять, как выбрать, какие поля возвращать. Похоже, у вас больше полей для исключения, чем для включения, поэтому будет проще перечислить те, которые нужно ВКЛЮЧИТЬ, а не ИСКЛЮЧИТЬ. - person Alex; 19.11.2012
comment
Спасибо... по какой-то причине, если есть только одно поле за пределами указанного фрагмента, он возвращает все поля. - person Tracker1; 20.11.2012
comment
db.listings.find({is_active:true}, {vehicle_id:1, Vehicle.mfg_make:1, ..., Vehicle.images:{$slice: 1}}).limit(1) - person Tracker1; 20.11.2012
comment
@ Tracker1 Одно поле за пределами, вероятно, _id, которое проецируется, если оно не исключено явно; однако приведенное выше не совсем работает, если вы указываете только срез; то, что вам нужно (сегодня), это {images:{$slice:1}, images:1, _id:0} - person nik.shornikov; 01.05.2013

В структуре агрегации у вас есть операторы $project и $first (доступно в MongoDB версии 4.4 и выше ) для получения желаемого результата:

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' }
        }
    } }   
])

или с помощью $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] }
        }
    } }   
])

или с помощью $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] }
        }
    } }   
])
person chridam    schedule 04.11.2020