Пн goose поиск документов по детским критериям - PullRequest
0 голосов
/ 03 мая 2020

Я пытаюсь найти все документы с указанным свойством c в дочернем элементе. Например, я хочу найти всех пользователей с активным дочерним элементом.

Это мои модели

const userSchema = new mongoose.Schema({
    child: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'child'
    }
});

const childSchema = new mongoose.Schema({
    active: {
        type: Boolean,
        default: true
    }
});

Я пробовал заполнять и сопоставлять (.populate({path:'child', match: {active: true}})), но получаю все пользователи со свойством child, равным NULL, если они не активны. Мне нужны только пользователи с активным ребенком. Все мои исследования направлены на использование точечного синтаксиса, но по любой причине я получаю пустой массив. Смотрите ниже:

let usersWithActiveChild = await User.find({'child.active': true}));
console.log(usersWithActiveChild) // --> displays '[]' 

Спасибо за вашу помощь!

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Когда вы используете ссылку для ссылки на другую схему, Mon goose сохраняет документы в отдельных коллекциях в MongoDB.

Фактическое значение, хранящееся в поле child пользовательского документа, равно DBRef.

Если вы посмотрите на данные непосредственно в MongoDB, вы найдете нечто похожее на это :

Пользовательская коллекция

{
  _id: ObjectId("5a934e000102030405000000")
  child: DBRef("child",ObjectId("5a934e000102030405000001"),"DatabaseName")
}

Дочерняя коллекция:

{

  _id: ObjectId("5a934e000102030405000001"),
  active: true
}

При заполнении пользовательского объекта Mon goose выбирает пользовательский документ, а затем выбирает ребенок. Поскольку пользовательские документы уже были получены, match в вызове populate фильтрует дочерние элементы, как вы заметили.

Пунктирная нотация 'child.active' может использоваться только в том случае, если дочерний элемент хранится в MongoDB в качестве вложенного документа, например

{
  _id: ObjectId("5a934e000102030405000000")
  child:{
    _id: ObjectId("5a934e000102030405000001"),
    active: true
  }
}

Но ваш дочерний элемент определяется как ссылка, так что это не будет в таком случае.

Чтобы отфильтровать список пользовательских документов на основе содержимого указанного дочернего элемента, вам нужно будет либо
- заполнить совпадение, как вы это сделали, а затем фильтр набор результатов или
- агрегат коллекция пользователей, поиск дочерние документы, а затем match дочернее поле.

0 голосов
/ 03 мая 2020

Это можно легко сделать с помощью инфраструктуры агрегирования.

Сначала мы объединяем две коллекции с помощью $ lookup . Результатом поиска является массив, но наше отношение с User и Child одно к одному, поэтому мы получаем первый элемент, используя $arrayElemAt: ["$child", 0].

И, наконец, мы применяем наш фильтр "child.active": true,, используя $ матч .

Детская площадка

  let usersWithActiveChild = await User.aggregate([
    {
      $lookup: {
        from: "childs",    //must be PHYSICAL collection name
        localField: "child",
        foreignField: "_id",
        as: "child",
      },
    },
    {
      $addFields: {
        child: {
          $arrayElemAt: ["$child", 0],
        },
      },
    },
    {
      $match: {
        "child.active": true,
      },
    },
  ]);

Примеры документов:

db={
  "users": [
    {
      "_id": ObjectId("5a834e000102030405000000"),
      "child": ObjectId("5a934e000102030405000000")
    },
    {
      "_id": ObjectId("5a834e000102030405000001"),
      "child": ObjectId("5a934e000102030405000001")
    },
    {
      "_id": ObjectId("5a834e000102030405000002"),
      "child": ObjectId("5a934e000102030405000002")
    },

  ],
  "childs": [
    {
      "_id": ObjectId("5a934e000102030405000000"),
      "active": true
    },
    {
      "_id": ObjectId("5a934e000102030405000001"),
      "active": false
    },
    {
      "_id": ObjectId("5a934e000102030405000002"),
      "active": true
    }
  ]
}

Вывод:

[
  {
    "_id": ObjectId("5a834e000102030405000000"),
    "child": {
      "_id": ObjectId("5a934e000102030405000000"),
      "active": true
    }
  },
  {
    "_id": ObjectId("5a834e000102030405000002"),
    "child": {
      "_id": ObjectId("5a934e000102030405000002"),
      "active": true
    }
  }
]

Или, как лучший подход, сначала нужно получить activ childs, а затем искать пользователей следующим образом:

db.childs.aggregate([
  {
    $match: {
      "active": true
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "_id",
      foreignField: "child",
      as: "user"
    }
  }
])

Playground

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...