1

I'm trying to search my collection for all occurrences where the body property contains all of the search keywords.

Example string - "The black cat is definitely purple."

Keywords "black", "purple" would return the string.

Keywords "black", "dog" would not return that string.

I've been cruising some topics and Googling, but cannot seem to find the proper syntax to do this.

Currently, I am taking an string of keywords separated by commas, exploding it into an array, and then putting that into a MongoRegex Object. I know my syntax is off, because when I send just one keyword it works, but when there is more than one, I do not get any results that I would expect to get.

Current Approach:

<?php

function search_topics($array)
{
    include_once('config.php');
    $collection = get_connection($array['flag']);

    $x = 0;
    $string = null;
    $search_results = null;
    $keywords = explode(',', $array['search']); 
    $end_of_list = count($keywords);

    while ($x < $end_of_list)
    {
        $string = $string."/".$keywords[$x];
        $x++;
        if($x >= $end_of_list)
        {
            $string = $string."/i";
        }
    }

    if ($string != null)
    {   
        try
        {
            $regex_obj = new MongoRegex($string);
            $cursor = $collection->find(array('body' => $regex_obj));
        }
        catch (MongoCursorException $e)
        {
            return array('error' => true, 'msg' => $e->getCode());
        }

        foreach($cursor as $post)
        {
            $search_results[] = $post;
        }

        if ($search_results != null && count($search_results) > 1)
        {       
            usort($search_results, 'sort_trending');
        }

        return array('error' => false, 'results' => $search_results);
    }
    else
    {
        return array('error' => false, 'results' => null);
    }
}
?>

So, if I send the string black in $array['search'], my object is formed with /black/i and would return that string.

If I send the string black,cat in $array['search'], my object is formed with /black/cat/i and returns null.

Can anyone point me in the right direction with this regex syntax stuff?

Thanks in advance for any help!

Nathan

nathansizemore
  • 3,028
  • 7
  • 39
  • 63
  • Here is some question about matching *all* words: http://stackoverflow.com/questions/5421952/how-to-match-multiple-words-in-regex –  Jul 31 '13 at 07:30

1 Answers1

3

Instead of regular expressions, I would suggest you look at MongoDB's text search functionality instead, which is specifically made for situations like this: http://docs.mongodb.org/manual/core/text-search/

You would use that like this (on the MongoDB shell):

use admin
db.runCommand( { setParameter: 1, 'textSearchEnabled' : 1 } );
use test
db.so.ensureIndex( { string: 'text' } );
db.so.insert( { string: "The black cat is definitely purple." } );
db.so.runCommand( 'text', { search: '"cat" AND "dog"' } )
db.so.runCommand( 'text', { search: '"cat" AND "purple"' } )

A command doesn't return a cursor, but instead it will return one document containing all the query results in the results field. For the last search command, the result is:

{
    "queryDebugString" : "cat|purpl||||cat|purple||",
    "language" : "english",
    "results" : [
        {
            "score" : 2.25,
            "obj" : {
                "_id" : ObjectId("51f8db63c0913ecf728ff4d2"),
                "string" : "The black cat is definitely purple."
            }
        }
    ],
    "stats" : {
        "nscanned" : 2,
        "nscannedObjects" : 0,
        "n" : 1,
        "nfound" : 1,
        "timeMicros" : 135
    },
    "ok" : 1
}

In PHP, for the runCommand to turn on text search, you'd use:

$client->database->command( array( 
    'setParameter' => 1, 
    'textSearchEnabled' => 1 
) );

And the text search itself as:

$client->database->command( array(
    'text' => 'collectionName', 
    'search' => '"cat" AND "purple"' 
) );
Derick
  • 35,169
  • 5
  • 76
  • 99
  • This will be used for returning more than one document most of the time. So, will this approach work since you say it returns one document instead of a cursor? – nathansizemore Jul 31 '13 at 13:23
  • Sure, it returns one document, but the ``results`` field of course returns multiple results if the search query finds those. – Derick Jul 31 '13 at 13:37
  • Maybe you can help with my latest try and your answer - http://stackoverflow.com/questions/17984262/no-results-with-text-search-mongodb-php – nathansizemore Aug 01 '13 at 02:39