Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
761 views
in Technique[技术] by (71.8m points)

php mongodb full-text search and sort

i nead to make a search with full text index and this code work:

$cursor=$collection->find(array('$text'=>(array('$search'=>$s))),
                    array("score"=> array('$meta'=>"textScore"))
        );

i try to sort the cursor with:

$cursor =$cursor->sort(array("score"=>1));

when i try to read

var_dump($cursor->getNext());

i gave me this error Uncaught exception 'MongoCursorException' with message 'localhost:27017: Can't canonicalize query: BadValue can't have a non-$meta sort on a $meta projection'

any idea?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are attempting to sort on a meta field, not a normal fieldname.

The second argument to $collection->find() determines which fields of the document you (do/do not) want to be returned by the query.

This is similar to SELECT *... vs SELECT field1, field2 ... in SQL databases.

Now, in MongoDB 2.6 there is an additional keyword you can use here, $meta. This keyword allows you to "inject" fieldnames into the return document (that otherwise would not actually exist). The value of this injected fieldname would come from some sort of "meta data" of the document or query you are executing.

The $text query operator is an example of an operator that has more information available about the matched document.. Unfortunately, it has no way of telling you about this extra information since doing so would manipulate your document in unexpected way. It does however attach a metadata to the document - and it is up to you to decide if you have need for it or not.

The meta data the $text operator creates uses the keyword "textScore". If you want to include that data, you can do so by assigning it to a field name of your choice:

array("myFieldname" => array('$meta' => 'keyword'))

For example, in the case of $text search (textScore) we can inject the fieldname "score" into our document by passing this array as the 2nd argument to $collection->find():

array("score" => array('$meta' => 'textScore'))

Now we have injected a field called "score" into our return document which has the "textScore" value from the $text search.

But since this is still just meta data of the document, if you want to continue to use this value in any subsequent operations before executing the query, you still have to refer to it as $meta data.

This means, to sort on the field you have to sort on the $meta projection

array('score' => array('$meta' => 'textScore'))

Your full example then becomes:

<?php
$mc = new MongoClient();


$collection = $mc->selectCollection("myDatabase", "myCollection");

$string = "search string";
$cursor = $collection->find(
    array('$text' => array('$search' => $string)),
    array('score' => array('$meta' => 'textScore'))
);

$cursor = $cursor->sort(
    array('score' => array('$meta' => 'textScore'))
);

foreach($cursor as $document) {
    var_dump($document);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...