2016-07-29 21 views
1

Ich wollte, dies zu tun:

model.User.aggregate([ 
    //step 1 match criteria 
    { 
     $match: criteria 
    }, 
    //step 2 skip 
    { 
     $skip: offset 
    }, 
    //step 3 limit 
    { 
     $limit: limit 
    }, 
    //step 4 sort by computed distance 
    { 
     $geoNear : { 
      near: {type: 'Point', coordinates: coords }, 
      distanceField: 'currentCity.computed_distance', 
      includeLocs: 'currentCity.loc', 
      spherical: true, 
      uniqueDocs: true, 
      distanceMultiplier: 3963.2, //convert to miles (this number is the radius of the earth in miles) 
     } 
    } 
],function(err,users){ 
    if (err) return res.error(err); 
    if (!users.length) return res.error('no matched criteria'); 
    res.apiResponse(users); 
}); 

aber die Dokumentation von $ geoNear Zustände:

Sie nur $ verwenden können geoNear als erste Stufe einer Pipeline.

der Dokumentation Lesen, ich sehe, dass ich einfach $match innerhalb von $geoNear über die query Option bewegen kann. Ebenso kann $limit in $geoNear über die Option limit platziert werden. Das einzige Problem ist, gibt es keine Entsprechung für die $skip Option, so dass es aussieht, als wäre erleichtern Seitenumbruch nicht möglich? Ich bin hier wirklich verwirrt, warum $geoNear nicht der vierte Schritt in der Pipeline sein kann. Das Ziel der Abfrage ist einfach, die besten n Übereinstimmungen zu finden, wobei n = limit, dann sortiert nach nächsten in der Nähe. ist das überhaupt möglich? Ich habe Probleme, eine Antwort für diesen speziellen Anwendungsfall zu finden.

Ich nehme eine Lösung sein könnte, eine Abfrage auszuführen nur ids passenden Dokumente auswählen, um die Liste von IDs zu konvertieren, gehen Sie dann die Aggregate mit einer $in Abfrage wie folgt:

model.User.find(criteria).skip(offset).limit(limit).select('_id').exec(function (err, userIds) { 
    var ids = []; 
    userIds.forEach(function(u){ 
     ids.push(u._id); 
    }); 

    model.User.aggregate([ 
     { 
      $geoNear : { 
       query: { _id: {$in: $ids } }, 
       near: {type: 'Point', coordinates: coords }, 
       distanceField: 'currentCity.computed_distance', 
       includeLocs: 'currentCity.loc', 
       spherical: true, 
       uniqueDocs: true, 
       distanceMultiplier: 3963.2, //convert to miles (this number is the radius of the earth in miles) 
      } 
     } 
    ],function(err,users){ 
     if (err) return res.error(err); 
     if (!users.length) return res.error('no matched criteria'); 
     res.apiResponse(users); 
    }); 
}); 

Dies würde funktionieren, aber Idealerweise könnte ich es in 1 Abfrage tun, wenn möglich. irgendwelche Ideen sehr geschätzt.

Antwort

0

Eine Lösung ist dieses:

result = db.cafes.aggregate([{ 
'$geoNear': { 
    'near': { 
     'type': 'Point', 
     'coordinates': [ 
      -73.991084, 
      40.735863]}, 
    'spherical': True, 
    'distanceField': 'dist', 
    'num': 20} 
}, { 
    '$skip': 10 
}]) 

Es gibt auch eine bessere Lösung mit diesem Ansatz:

ids = [42] 

result = db.command(
'geoNear', 'cafes', 
near={ 
    'type': 'Point', 
    'coordinates': [ 
     -73.991084, 
     40.735863]}, 
spherical=True, 
minDistance=268, 
query={ 
    '_id': { 
     '$nin': ids}}, 
num=10) 

Und eine wirklich schöne Erklärung auf Geschwindigkeit und Fragen hier:

https://emptysqua.re/blog/paging-geo-mongodb/