如何在mongodb && php中首先返回具有特定值的结果

i have mongodb database and using that with php. i am searching for hotels from database. i want to search with "Chicago" city. for Chicago its destination code is "CHI".

I am getting result but problem is that I am getting other city in result also with same destination code. They are

  • Chicago
  • Hoffman Estates
  • Evanston
  • Addison.

now I want to fire short or order_by in such way that, if I search for chicago, all chicago hotels must come first than other come.

I can not use "sort{'city':1}" , because if user search "Evanston" city than this city result will not come at top.

how can i do this??? thank in advance.

As of MongoDB 2.6, this isn't possible in a find() query. You are asking to take the same query, with the same sort key

> db.hotels.find(query, project).sort(sort_key)

and return results in a different order by assigning something like a priority to different values (search Evanston, Evanston is highest priority). The best way to do this will be to use a sort_by() function in your client language.

One approach to this and not the most performant way to "dynamically rank" would be to use the aggregation framework in your second query once you have identified the city code. That city code could be done as part of a "auto-complete" which makes things nice and clean on the city selection as well.

Here you basically rank the queried "city" as the highest. But of course "city" needs to be a field in your collection as well:

db.collection.aggregate([
    // Match all documents by "cityCode"
    { "$match": { "cityCode": "CHI" } },

    // Score the documents with matching city
    { "$project": {
        "city": 1,
        "score": { "$cond": [ { "$eq": [ "$city", "Evenston" ] }, 1, 0 ]}
    }},

    // Sort by score descending, so highest first
    { "$sort": { "score": -1 } }
])

An approach along those lines is reasonable but it does need the aggregation framework to process the documents and then sort them in order to place the results that are highest.

For me though, If I was "hotel matching", then in both my "cities" collection where I kept the relation of "cityCode" to "city" by name and in my "hotels" collection I would store the geoLocation co-ordinates that were general for the "city" and for the actual "hotel" location. This way I could get the co-ordinates matching the response and basically issue the query to find which is "nearest":

db.collection.find({
    "cityCode": "CHI",
    "location": {
        "$nearSphere": {
            "$geometry": {
                "type": "Point",
                "coordinates": [ 87.6947, 42.0464 ]
            }
        }
    }
})

So you would "extract" the coordinate data for "Evanston" from your "cites" collection and use that to compare to the "location" field where the "hotel" is actually situated. This "nearest" approach naturally ranks by distance from the given coordintes so all results are in order of "nearest" to "furthest" away.

If you need more flexibility in your overall "ranking" you can use the $geoNear form for the aggregation pipeline instead, which allows you to return more results and or play with the sort order and other calculated fields:

db.collection.aggregate([
    { "$geoNear": {
        "near": { "type": "Point", "coordinates": [ 87.6947, 42.0464 ] },
        "distanceField": "distance",
        "query": { "cityCode": "CHI" },
        "num": 200,
        "spherical": true
    }}

    // Other pipeline stages
    { ... }
])

Apart from other customization's, this "projects" a "distanceField" as specified into the document so you can use that value later.

But you basically need another form of ranking. You can either manually assign as in the first example, but for me the natural fit seems to be to add geospatial data and indexing.