Как я могу объединить, используя совпадение на двух разных полях? - PullRequest
1 голос
/ 10 апреля 2020

Это кажется достаточно простым, но по какой-то причине, когда я помещаю второе поле в свой оператор сопоставления, моя агрегация возвращает пустой массив.

Я проверил это:

Объединение совпадений в текстовом поле с совокупностью

Соответствие двух разных полей в Пн goose, Агрегат?

Mongodb сравнивает два поля с совокупным значением сопоставленных полей

Это то, что я хочу:

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

$match: 
{ $and: 
  [ 
    { createdByUserId: userId }, 
    { dateStart: { $gte: new Date(startDate) } } 
  ] 
}

, это то, что он разрешает, чтобы быть :

{
  "$match": {
    "$and": [
      {
        "createdByUserId": "5e6c2dddad72870c84f8476b"
      },
      {
        "dateStart": {
          "$gte": "2020-04-10T14:35:02.478Z"
        }
      }
    ]
  }
}

ЭТО ТО, ЧТО Я ПОПРОБОВАЛ

Я попытался упростить проблему, просто используя createByUserId -but-, который не работает

Я полагаю, что совпадение идентификатора пользователя - это суть моей проблемы это (но это не сработало)

$match: 
{
    createdByUserId: { $eq: {$toOjbectId:userId} }
}

Разрешено:

{
  "$match": {
    "createdByUserId": {
      "$eq": {
        "$toOjbectId": "5e6c2dddad72870c84f8476b"
      }
    }
  }
}

Подробнее

Чтобы показать весь конвейер, вот мое агрегирование:

var match = {
    $match: 
    { $and: 
        [ 
            { createdByUserId: userId }, 
            { dateStart: { $gte: new Date(startDate) } } 
        ] 
    }
};

var lookup ={
    $lookup:
    {
        from: "MyEvents",
        localField: "_id",
        foreignField: "eventId",
        as: "SignedUpUsers"
    }
};

var project = {
    $project: {
        "_id": 1,
        "name": 1,
        "dateStart": 1,
        "createdByUserId": 1
    }
};

var agg = [
    match,
    lookup,
    project
];

Event.aggregate(agg)
.sort({dateStart: 1})
.then( events => {
    if(events){
        return resolve(events);
    }else{
        return reject(null);
    }
})
.catch(err => {
    return reject(err);
})

Вот схема событий

const EventSchema = new Schema({
    name: {type: String, required: true},
    dateStart: {type: Date, required: true},
    createdByUserId: {type: Schema.Types.ObjectId, required: true},
})

Вот схема MyEvents

const MyEventsSchema = new Schema({
    userId: {type: Schema.Types.ObjectId, required: true},
    eventId: {type: Schema.Types.ObjectId, required: true},
})

(в коллекции есть данные, которые должны быть возвращены)

Как сопоставить два разных поля?

ОБНОВЛЕНИЕ

Спасибо whoami , это работает:

const mongoose = require("mongoose");

 {
   $match: {
     createdByUserId: mongoose.Types.ObjectId(userId);
   }
 }

Но кто-нибудь может сказать мне, почему это не меняет строку на идентификатор объекта:

{$toOjbectId:userId}

Ответы [ 2 ]

2 голосов
/ 10 апреля 2020

Да, проблема должна быть связана с вводом типа string Vs Поле БД имеет тип ObjectId(). Три способа сделать это:

One Way: Изменение в агрегационном запросе

 {
    $match: {
      $expr: {
        $eq: [
          userId,
          {
            $toString: "$createdByUserId" // Convert existing 'ObjectId()' to String
          }
        ]
      }
    }
  }

Тест: MongoDB-Playground

Второй способ: Преобразование string до ObjectId() в пн goose:

const mongoose = require("mongoose");

    {
      $match: {
        createdByUserId: mongoose.Types.ObjectId(userId);
      }
    }

Третий способ:

db.collection.aggregate([
  {
    $match: {
      $expr: {
        $eq: [
          {
            $toObjectId: "5e6c2dddad72870c84f8476b" /** Convert input to ObjectId() using aggregation */
          },
          "$createdByUserId"
        ]
      }
    }
  }
])

Тест: MongoDB-Playground

Проблема с вашим запросом: Так как $ObjectId является оператором агрегирования - вам необходимо использовать синтаксис агрегации в $match.

I предпочел бы второй процесс, так как он может иметь лучшую производительность и использовать индекс в поле createdByUserId. В любом случае вы всегда можете использовать explain для проверки производительности вашего запроса.

0 голосов
/ 10 апреля 2020

Вы можете следовать этому коду

$match: {
    $and: [
      {
        "createdByUserId": "5e6c2dddad72870c84f8476b"
      },
      {
        "dateStart": {
          $gte: "2020-04-10T14:35:02.478Z"
        }
      }
    ]
  }
...