В MongoDB у меня есть модели User, Token и Boost.

У пользователя может быть один или несколько жетонов и одно или несколько повышений.

Token имеет поле местоположения 2dsphere.

И Boost имеет поля даты startTime и stopTime.

Считается, что у пользователя активный импульс, если Date.now() больше boost.startTime() и меньше boost.stopTime().

Какую агрегацию Mongo я могу написать, чтобы получить все токены рядом с определенным местоположением, которые принадлежат пользователям с хотя бы одним активным ускорением?

1
Chidi Williams 11 Сен 2018 в 03:48

1 ответ

Лучший ответ

На основании вашего вопроса я создал фиктивные данные

token collection:
{
    "_id" : ObjectId("5b97541c6af22cc65216ffd8"),
    "userid" : "5b9753726af22cc65216ffd6",
    "location" : {
        "longitude" : 80.250875,
        "latitude" : 13.052519
    }
},
{
    "_id" : ObjectId("5b97543a6af22cc65216ffd9"),
    "userid" : "5b97537e6af22cc65216ffd7",
    "location" : {
        "longitude" : 80.249995,
        "latitude" : 13.051819
    }
}

boost collection :
{
        "_id" : ObjectId("5b9754796af22cc65216ffda"),
        "startTime" : ISODate("2018-09-11T05:36:57.149Z"),
        "stopTime" : ISODate("2018-09-11T05:36:57.149Z"),
        "userid" : "5b9753726af22cc65216ffd6"
    },
    {
        "_id" : ObjectId("5b9754b46af22cc65216ffdb"),
        "startTime" : ISODate("2018-10-08T18:30:00.000Z"),
        "stopTime" : ISODate("2018-10-08T18:30:00.000Z"),
        "userid" : "5b97537e6af22cc65216ffd7"
    }

Users collection :
{
            "_id" : ObjectId("5b9753726af22cc65216ffd6"),
            "userName" : "user111"
        },
        {
            "_id" : ObjectId("5b97537e6af22cc65216ffd7"),
            "userName" : "user222"
        }

Совокупный запрос на выборку всех токенов рядом с определенным местоположением, принадлежащих пользователям с хотя бы одним активным повышением, выглядит следующим образом:

 db.token.aggregate([
{
     "$geoNear": {
        "near": { type: "Point", coordinates: [80.248797,13.050599] },
        "distanceField": "location",
        "maxDistance": 1000,
        "includeLocs": "location",
        "spherical": true
     }
   },
   {"$lookup" : {"from":"boost",
                 "localField" : "userid",
                "foreignField" : "userid",
                 "as" : "boostDocs"
      }},
   {"$unwind" : "$boostDocs"},
   {"$match" : {"$and":[{"boostDocs.startTime":{"$lte":new Date("11/09/2018")}},{"boostDocs.stopTime":{"$gte":new Date("10/09/2018")}}]}}
   ])

Обратите внимание, что запрос на соответствие местоположению находится в верхней части запроса, поскольку $ geoNear будет работать только в том случае, если это первая стадия конвейера агрегации. Дата, которую я использовал для сравнения, - это просто проверить, работает ли мой запрос. Вы можете указать дату или Date.now () в соответствии с вашими требованиями.

1
Vish511 11 Сен 2018 в 06:40