2013-06-02 3 views
12

Je me demandais s'il était possible de combiner une recherche de texte et d'exécuter une requête géospatiale sur les résultats/comment je le ferais. J'utilise Mongoose pour le moment mais ça ne me dérange pas d'utiliser directement Mongo pour les commandes.MongoDB: combiner la recherche de texte et la requête géospatiale

Ce que j'essaie de faire est de permettre à l'utilisateur de rechercher un produit et de retourner les résultats qui sont dans un endroit particulier. J'ai les deux commandes en cours d'exécution séparément, mais je n'arrive pas à comprendre comment les combiner.

Répondre

3

Vous pouvez filtrer une recherche de texte en ajoutant un paramètre de filtre (j'utilise node-mongodb-native):

db.command({ text: 'thecollection', search: searchString, filter: query }, function(err, o) { 

    if (err) throw err; 

    var results = o.results.map(function(result) { return result.obj }); 

    // process the response ... 

    }); 

Si elle est une recherche géographique approximative que vous voulez faire, vous pouvez filtrer vos résultats en définissant un min et max autour de votre latitude longitude:

var distances = {'200m': 0.002, '500m': 0.005, '1km': 0.01, '5km': 0.05 } 

    , distance = distances[reqDis]; 


var query = { 
    latitude: { $lt: reqLat+distance, $gt: reqLat-distance }, 
    longitude: { $lt: reqLng+distance, $gt: reqLng-distance } 
}; 

// put the query in the db.command as described above 

Voici quelque chose sur le sujet dans la documentation de MongoDB: http://docs.mongodb.org/manual/tutorial/limit-number-of-items-scanned-for-text-search/

+1

puis-je utiliser $ opérateurs lt et gt $ si la latitude et la longitude sont stockées dans un tableau ; quelque chose comme- loc: [50.433234,20,220123] –

4

Mongo DB ne supporte pas la recherche de texte et de géo en même temps. [Envoyer cette] (http://docs.mongodb.org/manual/reference/limits/#Queries-cannot-use-both-text-and-Geospatial-Indexes)

Vous pouvez le faire en suivant

  1. Essayez regex pour le texte et à proximité de la recherche spatiale.

    var aggregate=YourCollection.aggregation() 
    aggregate.near({ 
        near:coord, 
        includeLocs: "loc", 
        distanceField: "distance", 
        maxDistance: distance 
    }); 
    aggregate.match({name:{$regex:keyword,$options: 'i'}}) 
    aggregate.exec(function(err,yourDocuments){ 
        //your smart code 
    }) 
    
  2. recherche d'utilisation pour index de texte et utilisation requête suivante pour les documents les plus proches, son juste en face de ce que dit.

    var aggregate=YourCollection.aggregate(); 
    var match= { 
        latitude: { $lt: yourCurrentLatitude+maxDistance, $gt: yourCurrentLatitude-maxDistance }, 
        longitude: { $lt: yourCurrentLongitude+maxDistance, $gt: yourCurrentLongitude-maxDistance }, 
        {$text:{$search:keyword}} 
    }; 
    
    
    aggregate.match(match).exec(function(err,yourDocuments){//your smart code}) 
    

` 3. diviser les documents en pièces à l'aide MapReduce. Filtrez les doucmets soit par text/geo search et stockez-le dans une nouvelle collection. Passez en revue la nouvelle collection et trouvez la collection exacte par le filtre de remainig.

YourCollection.mapReduce(map, reduce, {out: {inline:1, query : yourFirstQuery}}, function(err, yourNewCollection) { 
    // Mapreduce returns the temporary collection with the results 
     collection.find(yourNewQuery, function(err, result) { 
      //your awsome code 
     }); 
    }); 
4

Ceci est une exigence très commune où la recherche de filtre géographique et le texte est nécessaire dans un cas d'utilisation qui est malheureusement pas directement pris en charge par mongodb encore. Le code ci-dessous utilise le pilote mongoose, filtre les documents en fonction de l'emplacement (longitude et latitude), puis d'autres filtres basés sur le terme recherché.

var area = { 
    center: [51, -114], //lng = 51 and lat = -114 
    radius: 100, 
    unique: true //this option is deprecated from MongoDB 2.6 on as mongodb no longer returns duplicate results 
}; 

var query = Post.where('loc').within().circle(area) //Step 1: filter based on location 
    //Step 2: Next filter on the basis of searched text 
    .where({ 
     $text: { 
      $search: <searchTerm> 
     } 
    }, { 
     score: { 
      $meta: 'textScore' 
     } 
    }) 
    //Step 3: Filter any document fields that should not be returned in the result 
    .select({ 
     "val1": 0, 
     "val2": 0 
    }); 

//Execute the query 
query.exec(function (err, result) { 
    if (err) { 
     //return error in the response 
    } 
    //return result object in the response 
}); 

Dans ce code "Post" est un schéma mangouste quelque chose comme ci-dessous

var PostSchema = new Schema({ 
    title: String, 
    description: String, 
    loc: { 
     type: [Number], // [<longitude>, <latitude>] 
     index: '2d' // create the geospatial index 
    } 
    //some other fields 
} 

module.exports = mongoose.model('Post', PostSchema); 

également pour la zone de recherche, il y a d'autres options disponibles comme la boîte

var lowerLeft = [40.73083, -73.99756] 
var upperRight= [40.741404, -73.988135] 
query.where('loc').within().box(lowerLeft, upperRight) 

Pour les deux Géolocalisation recherche et la recherche de texte pour travailler, assurez-vous d'avoir index sur le champ loc et le champ de texte. Plus de détails ici. loc Search et text search

0

La recherche de texte complet est possible avec géospatial.

Vous pouvez essayer en shell mongo:

db.collection.aggregate([ 
    { "$geoNear": { 
     "near": { 
      "type": "Point", 
      "coordinates": [ 
       -73.86, 
       41.076 
      ] 
     }, 
     "spherical": true, 
     "maxDistance": 600, 
     "distanceField": "distance", 
     "query": { 
      "fieldname": /querystring/ 
     } 
    }} 
]) 

Utilisation de la recherche en texte intégral:

db.collection.find({ 
    "$text": { "$search": "query string" }, 
    "location": { // this will your field name 
     "$geoWithin": { 
      "$centerSphere": [[ 
       -73.86, 
       43.03 
      ], 500 ] 
     } 
    } 
}) 
Questions connexes