2017-06-18 1 views
1

J'utilise cosmos azur db comment créer l'index et d'interroger le top 10 l'utilisateur le plus proche si le document est comme celui-ci, en C#:Créer Geo Index et requête à proximité

{ 
    "_id" : "146138792054898475572", 
    "email" : "[email protected]", 
    "firstName" : "abc", 
    "lastName" : "abc", 
    "loc" : { 
    "lat" : 31.5200788, 
    "lng" : 74.3236112 
    }, 
    "gender" : "Male", 
    "deviceId" : "YWg8crAjZLCrV", 
    "createdDate" : ISODate("2017-06-11T11:35:41.601Z"), 
    "updatedDate" : ISODate("2017-06-17T17:33:10.743Z") 
} 

Requête:

db.User.find(
    { 
     "loc": 
     { $near : 
      { 
      $geometry: { type: "Point", coordinates: [ 31.5200788, 74.3236112 ] }, 
      $minDistance: 1000, 
      $maxDistance: 5000 
      } 
     } 
    } 
) 
+0

Donc, vous essayez de faire une requête spatiale? Qu'avez-vous essayé? Vous avez seulement montré votre document, sans tentative de requête, aucune sortie, et aucune erreur spécifique. Votre base de données est-elle définie sur API DocumentDB ou API MongoDB? Cela fait une grosse différence. Je devine MongoDB basé sur les propriétés et le tag, mais vous devriez confirmer. –

+0

@DavidMakogon querry ajouté –

+0

aucun résultat affiché lorsque j'ai essayé –

Répondre

2

Voici quelques problèmes liés principalement à la manière dont vous avez stocké les documents. MongoDB prend en charge le stockage d'un point de coordonnées dans l'un des trois formats:

  • héritage paires de coordonnées que l'ensemble Lorsque les données sont énumérées dans la longitude et puis commande latitude

    [ 74.3236112, 31.5200788 ] 
    
  • héritage paires de coordonnées en tant que un objet Où les données peuvent être organisées par des clés nommées, mais ces doivent être commandés et nommés explicitement comme "lon" et "lat" respectivement "pour":

    { "lon": 74.3236112, "lat": 31.5200788 } 
    
  • Comme GeoJSON le format où les données stockées peuvent être tout format d'objet GeoJSON valide. Pour un type "Point" est ce:

    { 
        "type": "Point", 
        "coordinates": [ 74.3236112, 31.5200788 ] 
    } 
    

Pour démontrer que j'ai une collection avec votre exemple de document en quatre formats différents. Nous allons créer un index sur cette collection avec .createIndex({ "loc": "2dsphere" }) puis utiliser le pipeline d'agrégation $geoNear pour interroger et retourner la distance réelle du point interrogé:

db.geotest.aggregate([ 
    { "$geoNear": { 
    "near": { 
     "type": "Point", 
     "coordinates": [ 74.3236112, 31.5200788 ] 
    }, 
    "spherical": true, 
    "distanceField": "distance" 
    }} 
]) 

montre les quatre formats différents et la distance calculée de la requête . Notez que seuls les deux « valides » formats renvoient la distance correcte de 0 de l'emplacement de la requête:

{ 
     "_id" : ObjectId("5945f800b4051c7e52c90d1c"), 
     "email" : "[email protected]", 
     "firstName" : "abc", 
     "lastName" : "abc", 
     "loc" : { 
       "type" : "Point", 
       "coordinates" : [ 
         74.3236112, 
         31.5200788 
       ] 
     }, 
     "gender" : "Male", 
     "deviceId" : "YWg8crAjZLCrV", 
     "createdDate" : ISODate("2017-06-11T11:35:41.601Z"), 
     "updatedDate" : ISODate("2017-06-17T17:33:10.743Z"), 
     "distance" : 0 
} 
{ 
     "_id" : ObjectId("5945f8f6b4051c7e52c90d1e"), 
     "email" : "[email protected]", 
     "firstName" : "abc", 
     "lastName" : "abc", 
     "loc" : { 
       "lon" : 74.3236112, 
       "lat" : 31.5200788 
     }, 
     "gender" : "Male", 
     "deviceId" : "YWg8crAjZLCrV", 
     "createdDate" : ISODate("2017-06-11T11:35:41.601Z"), 
     "updatedDate" : ISODate("2017-06-17T17:33:10.743Z"), 
     "distance" : 0 
} 
{ 
     "_id" : "146138792054898475572", 
     "email" : "[email protected]", 
     "firstName" : "abc", 
     "lastName" : "abc", 
     "loc" : { 
       "lat" : 31.5200788, 
       "lng" : 74.3236112 
     }, 
     "gender" : "Male", 
     "deviceId" : "YWg8crAjZLCrV", 
     "createdDate" : ISODate("2017-06-11T11:35:41.601Z"), 
     "updatedDate" : ISODate("2017-06-17T17:33:10.743Z"), 
     "distance" : 5315650.25629941 
} 
{ 
     "_id" : ObjectId("5945f8b7b4051c7e52c90d1d"), 
     "email" : "[email protected]", 
     "firstName" : "abc", 
     "lastName" : "abc", 
     "loc" : { 
       "lat" : 31.5200788, 
       "lon" : 74.3236112 
     }, 
     "gender" : "Male", 
     "deviceId" : "YWg8crAjZLCrV", 
     "createdDate" : ISODate("2017-06-11T11:35:41.601Z"), 
     "updatedDate" : ISODate("2017-06-17T17:33:10.743Z"), 
     "distance" : 5315650.25629941 
} 

Ainsi, afin d'interroger correctement, vous avez besoin d'un « valide » le format pour l'indice.Personnellement, je recommande d'utiliser le format GeoJSON car il est largement utilisé comme standard, et vous donne également la possibilité de stocker tout objet GeoJSON valide par opposition à seulement "coordonnées de point".

Vous pouvez convertir les données avec une opération comme ce qui suit:

var ops = []; 

db.User.find({ 
    "loc.lng": { "$exists": true }, 
    "loc.lat": { "$exists": true } 
}).forEach(function(doc) { 
    ops.push({ 
    "updateOne": { 
     "filter": { "_id": doc._id }, 
     "update": { 
     "$set": { 
      "loc": { 
      "type": "Point", 
      "coordinates": [ doc.loc.lng, doc.loc.lat ] 
      } 
     } 
     } 
    } 
    }); 
    if (ops.length >= 1000) { 
    db.User.bulkWrite(ops); 
    ops = []; 
    } 
}); 

if (ops.length > 0) { 
    db.User.bulkWrite(ops); 
    ops = []; 
} 

Cette réécrira les "loc" données au format corrigé pour l'index et requête fonctionneront.

Vous devriez en fait vraiment faire un .dropIndexes() sur la collection avant de mettre à jour pour économiser sur le coût d'écriture, puis recréer l'index une fois terminé. Ce n'est pas une étape nécessaire, mais ce serait recommandé.

N.B. également l'argument $minDistace ici avec les données corrigées serait en fait encore à exclure le résultat, comme l'a démontré la distance réelle du point interrogé (ce qui est les mêmes coordonnées) est 0. Donc, supprimez cette contrainte lors des tests, ou mieux encore testez avec $geoNear comme démontré.

Notez également Il est fait mention de DocumentDB, qui ne prend pas en charge les protocoles de pipeline d'agrégation. Les exemples ici fonctionnent contre MongoDB sans problème, et sont principalement ici pour démontrer le problème de "format" avec les données. Régulier $near et other geospatial general queries are supported. Mais les données doivent être dans le bon format supporté.

2

Vos coordonnées sont en arrière. Par MongoDB docs:

Si vous utilisez longitude et la latitude, indiquez les coordonnées dans l'ordre de: longitude, latitude.

Vous devez inverser vos coordonnées:

db.User.find(
    { 
     "loc": 
     { $near : 
      { 
      $geometry: { type: "Point", coordinates: [ 74.3236112, 31.5200788 ] }, 
      $minDistance: 1000, 
      $maxDistance: 5000 
      } 
     } 
    } 
) 

Aussi, dans votre propriété loc, la commande est la longitude, la latitude (le vôtre est inversée dans le doc vous montriez).

+0

toujours aucun résultat –

+0

@MalikKashmiri Le balise ici est '$ maxDistance: 5000' puisque le point donné dans le document dans la question est" plus loin "que la contrainte fournie. Supprimez-le avec l'ordre corrigé de longitude puis la latitude et la requête renvoie le document. –