How to select subdocuments with MongoDB

青春壹個敷衍的年華 提交于 2019-12-29 04:48:06

问题


I have a collection with a subdocument tags like :

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

I want to select all the tags who start with a pattern, but returning only the matching tags.

I already use a regex but it returns all the news containing the matching tag, here is the query :

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

My question is : How can I retrieve all the tags (only) who match the pattern ? (The final goal is to make an autocomplete field)

I also tried using distinct, but I didn't find a way to make a distinct with a find, it always returning me all the tags :(

Thanks for your time


回答1:


Embedded documents are not collections. Look at your query: db.news.find will return documents from the news collection. tags is not a collection, and cannot be filtered.

There is a feature request for this "virtual collection feature" (SERVER-142), but don't expect to see this too soon, because it's "planned but not scheduled".

You can do the filtering client-side, or move the tags to a separate collection. By retrieving only a subset of fields - only the tags field - this should be reasonably fast.

Hint: Your regex uses the /i flag, which makes it impossible to use indexation. Your db strings should be case-normalized (e.g. all upper case)




回答2:


A bit late to the party, but hopefully will help others who are hunting for a solution. I've found a way to do this using the aggregation framework and combining $project and $unwind with the $match, by chaining them together. I've done it using PHP but you should get the gist:

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

The first match and project are just use to filter out to make it faster, then the unwind on subcollection spits out each subcollection item by item which can then be filtered using the final match.

Hope that helps.

UPDATE (from Ryan Wheale):

You can then $group the data back into its original structure. It's like having an $elemMatch which returns more than one subdocument:

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

I translated this from Node to PHP, so I haven't tested in PHP. If anybody wants the Node version, leave a comment below and I will oblige.



来源:https://stackoverflow.com/questions/8861938/how-to-select-subdocuments-with-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!