MongoDB search to return only specific fields

785 views
Skip to first unread message

wookie

unread,
May 2, 2015, 9:44:56 AM5/2/15
to mongod...@googlegroups.com
I'm using the `$text` feature in MongoDB to search for certain words and want the result to return not the entire document but only the specific fields where this word appears.

I've created the `Text index` and do the search as below:
   
text_results = db.Info.find_one({'$and': [{'$text': {'$search': "Hello"}, 'Username': 'John Doe'}]})  
 
This returns the whole document only and I only want the specific fields where 'Hello' occurs.

Jim Popovitch

unread,
May 2, 2015, 9:05:32 PM5/2/15
to mongod...@googlegroups.com
If you know the fields (i.e. Subject, Title, etc.) you can specify them like this:

   text_results = db.Info.find_one({'$and': [{'$text': {'$search': "Hello"}, 'Username': 'John Doe'}]},{'_id':0, 'Subject':1, 'Title':1})    

Otherwise, I don't believe there is a way to return the field names that matched a query without re.search'ing each individual field returned by find_one.

-Jim P.

wookie

unread,
May 3, 2015, 11:56:40 AM5/3/15
to mongod...@googlegroups.com
Thanks

I tried projection to, but it returned all subdocuments in a document, even those that don't have 'Hello' in the field

As I'm trying to search specifically in the document where username is John Doe.

Stephen Steneker

unread,
May 6, 2015, 7:40:29 AM5/6/15
to mongod...@googlegroups.com
On Monday, 4 May 2015 01:56:40 UTC+10, wookie wrote:
I tried projection to, but it returned all subdocuments in a document, even those that don't have 'Hello' in the field

Hi,

A normal find() query and projection will return matches at the document level, as you have discovered.

If you want to limit/manipulate results to only include subdocuments matching specific criteria (eg. Username), you should be able to this in an aggregation query:
  http://docs.mongodb.org/manual/core/aggregation-pipeline/

Assuming you are using MongoDB 2.6 or newer, the general approach would be:
  - start with your $text match (this pipeline opereation can only appear once, and must be at the beginning of your aggregation query)
  - $unwind the subdocument array
  - $match against { username: 'John Doe' }
  - (optional) $group by '_id' to recombine the subdocuments

If you'd like to provide an example document, desired result, and your specific version of MongoDB someone can help with a suggested query. 

Regards,
Stephen

Stephen Steneker

unread,
May 6, 2015, 8:12:52 AM5/6/15
to mongod...@googlegroups.com
Hi,

I noticed you've also posted this question with more details (including an example document) on StackOverflow:
 http://stackoverflow.com/questions/30002639/mongodb-search-to-return-only-specific-fields

If you need to do a text search match and then limit subdocuments to those that match the same text search expression, this isn't achievable with your current schema using the aggregation framework. The $text aggregation step can only appear once in an aggregation pipeline (as at MongoDB 3.0).

Some alternatives to consider:

 - You could change the schema so the expenses are stored as documents rather than subdocuments. Note: depending on how many subdocuments you envision adding to the array, this might be a better approach for performance (see: http://askasya.com/post/largeembeddedarrays).

 - If you don't need to do a text search match (i.e. with language stemming) you could refine the match using regular expressions in the aggregation pipeline.

 - Retrieve the matching documents and filter the subdocuments in your client side code. This isn't ideal if you are using text search, as your client code would have to apply similar stemming/tokenising to identify the matching subdocuments).

Regards,
Stephen
Reply all
Reply to author
Forward
0 new messages