Mongoose:如何使用填充进行查找

问题描述 投票:0回答:1

我想知道如何对数据库进行查询,得出满足“store”{name}字段的所有结果,但是这个“store”是用“_id”保存的,我使用 .populate() 来带来我的信息

/**示例:await Product.find({store:{name:"具体商店"}})*/

const products = await Product.find({ 'store.name' : "Ejemplo1" })
                .populate('store', 'name')

方案如下:

const storeSchema = mongoose.Schema({
   _id:"it is added automatically by mongoose",
   name: String
})
export default model('Store', storeSchema);

const productSchema = mongoose.Schema({
   store: {
     type: Schema.Types.ObjectId,
     ref: "Store"
   }
})

基本上我想要实现的是从数据库中提取具有特定“商店”的所有产品,但我仍然无法做到这一点,我感谢任何解决此问题的帮助,无论是参考还是示例合适的查询,提前谢谢

我尝试过这个: const p = 等待 Product.find({}) .填充({ 路径:'商店', 匹配:{ name: { $eq: 'Store1' } }, 选择:'名称-_id', })

但它返回整个集合并且不进行过滤,我收到如下内容: { _id:1, ... 存储:空, ... } { _id:2, ... 商店:{名称:"商店1"}, ... } { _id:3, ... 商店:{名称:“商店2”}, ... }

node.js mongodb mongoose mongoose-schema mongoose-populate
1个回答
0
投票

我想到的第一个解决方案是使用

Array.filter()
方法手动过滤数据。这很简单,如下所示:

const products = await Product.find({}).populate({
  path: 'store',
  match: { name: { $eq: 'Store1' } },
  select: 'name -_id'
});
const productsFiltered = products.filter(
  product => product.store !== null
);

如您所见,这对于检索少量数据很有帮助,并且易于实现。但如果您想在数据库级别应用此类过滤器,那么我们需要更改您产品的架构。因为根据 Mongoose 文档 不可能过滤查找数据。我引用以下推理:

例如,假设您

populate()
一个故事的
author
并且
author
不满足
match
。那么故事的
author
将是
null

const story = await Story.
  findOne({ title: 'Casino Royale' }).
  populate({ path: 'author', name: { $ne: 'Ian Fleming' } }).
  exec();
story.author; // `null`

一般来说,无法让

populate()
根据故事
author
的属性来过滤故事。例如,以下查询不会返回任何结果,即使填充了
author

const story = await Story.
  findOne({ 'author.name': 'Ian Fleming' }).
  populate('author').
  exec();
story; // null

如果您想按作者姓名过滤故事,您应该使用 denormalization

我建议您阅读 MongoDB 的官方博客文章。

我们可以应用博客文章中提到的不同类型的非规范化,但我将为其中一种类型提供代码。首先我们需要更改您的产品架构:

const productSchema = mongoose.Schema({
   store: {
     id: Schema.Types.ObjectId,
     name: String
   }
});

我们没有将

store
字段定义为对
Store
模型的引用,而是反规范化并添加了
id
(用于进行应用程序级连接)和
name
(用于过滤)字段。之后我们就可以轻松获取并过滤指定店铺名称的商品了:

const p = await Product.find({
  'store.name': 'Store1'
}, 'name -_id');

这样,我们将始终根据

store.name
字段过滤结果。如果我们想提供
id
name
字段以外的存储数据,我们需要进行应用程序级连接:

// Map each product to retrieve only their store ids and filter out to have unique store ids
const storeIds = p
  .map(
    product => product.store.id
  )
  .filter(
    (value, index, array) => array.indexOf(value) === index
  );

// Retrieve stores with given store ids
const stores = await Store.find({ _id: { $in: storeIds } });

// Join stores with each product's store.id
p.forEach(
  product => {
    product.store = stores.find(store => store._id.toString() == product.store.id.toString())
  }
);

正如您所看到的,使用非规范化有一些优点和缺点。当您想要更新商店名称时,您还需要更新该商店的产品中出现的所有内容。此更新可能会很昂贵。因此,如果您要对产品进行大量读取操作(使用商店名称过滤)并且不经常对商店进行名称更新,那么非规范化是一个不错的选择,那么这是一个很好的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.