Как выбрать субдокументы с помощью MongoDB

У меня есть коллекция с такими поддокументами, как:

Collection News :
   title (string)
   tags: [tag1, tag2...]

Я хочу выбрать все теги, которые начинают с шаблона, но возвращают только теги соответствия.

Я уже использую регулярное выражение, но он возвращает все новости, содержащие соответствующий тег, вот запрос:

db.news.find( {"tags":/^proga/i}, ["tags"] ).sort( {"tags":1} ).
    limit( 0 ).skip( 0 )

Мой вопрос: как я могу получить все теги (только), которые соответствуют шаблону? (Конечная цель - создать поле автозаполнения)

Я также пробовал использовать разные, но я не нашел способ сделать отчетливым с помощью find, он всегда возвращает мне все теги: (

Спасибо за ваше время

Ответ 1

Встроенные документы не являются коллекциями. Посмотрите на свой запрос: db. news.find вернет документы из коллекции news. tags не является коллекцией и не может быть отфильтрован.

Есть запрос функции для этой "функции виртуальной коллекции" (SERVER-142), но не ожидайте увидеть это слишком рано, потому что он "запланирован, но не запланирован".

Вы можете выполнить фильтрацию на стороне клиента или переместить теги в отдельную коллекцию. извлекает только подмножество полей - только поле tags - это должно быть достаточно быстро.

Совет. В вашем регулярном выражении используется флаг /i, что делает невозможным использование индексации. Строки вашего db должны быть нормализованы (например, весь верхний регистр)

Ответ 2

Немного поздно для вечеринки, но, надеюсь, поможет другим, которые ищут решение. Я нашел способ сделать это, используя структуру агрегации и объединив $project и $unwind с $match, объединив их вместе. Я сделал это с помощью PHP, но вы должны получить суть:

    $ops = array(
        array('$match' => array(
                'collectionColumn' => 'value',
            )
        ),
        array('$project' => array(
                'collection.subcollection' => 1
            )
        ),
        array('$unwind' => '$subCollection'),
        array('$match' => array(
                subCollection.subColumn => 'subColumnValue'
            )
        )
    );

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

Надеюсь, что это поможет.

ОБНОВЛЕНИЕ (от Ryan Wheale):

Вы можете вернуть $group данные в свою первоначальную структуру. Это похоже на $elemMatch, который возвращает более одного поддокумента:

array('$group' => array(
        '_id' => '$_id',
        'subcollection' => array(
            '$push' => '$subcollection'
        )
    )
);

Я перевел это с Node на PHP, поэтому я не тестировал его на PHP. Если кто-то хочет версию Node, оставьте комментарий ниже, и я обяжусь.