简体   繁体   English

填充字段然后找到 - mongoose

[英]Populate field then find - mongoose

I have a Cheques and a Payees collection, every cheque has its corresponding Payee ID .我有一个Cheques和一个Payees集合,每张支票都有其对应的Payee ID

What I'm trying to do is to write some queries on cheques, but I need to preform the searching after populating the payee (to get the name)我想做的是在支票上写一些查询,但我需要在填充收款人后进行搜索(以获取姓名)

const search = req.query.search || "";
const cheques = await Cheque
    .find({
        isCancelled: false,
        dueDate: { $gte: sinceDate, $lte: tillDate }
    })
    .select("_id serial dueDate value payee")
    .skip(page * limit)
    .limit(limit)
    .sort({ dueDate: -1, serial: 1 })
    .populate({
        path: "payee",
        select: "name"
    })

I guess what I'm trying do is fit this somewhere in my code,我想我正在尝试做的是在我的代码中的某个地方安装它,

match: {
    name: { $regex: search, $options: "i" }
   },

I have tried to put the match within the populate, but then it will still find all cheques even if they don't satisfy the population match but populate as null.我试图将匹配放入填充中,但即使它们不满足填充匹配但填充为 null,它仍然会找到所有检查。

I hate this answer and I hope someone is going to post a better one, but I've surfed the web for that with no luck.我讨厌这个答案,我希望有人会发布一个更好的答案,但我已经在 web 上冲浪了,但没有运气。 The only method I was able to find is to use the $lookup method in aggregation.我能够找到的唯一方法是在聚合中使用$lookup方法。

So you'll have to change your code from calling .find() to .aggregate() .因此,您必须将代码从调用.find()更改为.aggregate()

It's not the sad news, it's great, stable and no problems at all.这不是坏消息,它很好,很稳定,完全没有问题。 but I hated that because it's going to change some patterns you might be following in your code.但我讨厌那样,因为它会改变您在代码中可能遵循的某些模式。

const search = req.query.search || "";
    const cheques = await Cheque
        .aggregate([
             {
               $lookup: { // similar to .populate() in mongoose
                from: 'payees', // the other collection name
                localField: 'payee', // the field referencing the other collection in the curent collection
                foreignField: '_id', // the name of the column where the cell in the current collection can be found in the other collection
                as: 'payee' // the field you want to place the db response in. this will overwrite payee id with the actual document in the response (it only writes to the response, not on the database, no worries)
             },
             { // this is where you'll place your filter object you used to place inside .find()
               $match: {
                 isCancelled: false,
                 dueDate: { $gte: sinceDate, $lte: tillDate }
                 'payee.branch': 'YOUR_FILTER', // this is how you access the actual object from the other collection after population, using the dot notation but inside a string.
               }
             },
             { // this is similar to .select()
               $project: {_id: 1, serial: 1, dueDate: 1, value: 1, payee: 1}
             },
             {
               $unwind: '$payee' // this picks the only object in the field payee: [ { payeeDoc } ] --> { payeeDoc }
             }
        ])
        .skip(page * limit)
        .limit(limit)
        .sort({ dueDate: -1, serial: 1 })

Notice how you can no longer chain .select() and .populate() on the model query the way you used to do it on .find() , because now you're using .aggregate() which returns a different class instance in mongoose.请注意,您如何不能再像以前在.populate()上那样在 model 查询上链接.select()和 .populate .find() ,因为现在您使用的是.aggregate() ,它返回一个不同的 class 实例mongoose。

  • you can call .projcet() instead of doing it inside the aggregation array if you want to, but as far as I know, you can't use the .select() method.如果你愿意,你可以调用.projcet()而不是在聚合数组中执行它,但据我所知,你不能使用.select()方法。

My opinion-based solution to this problem is to include the payee information you need for filtering in the Cheque collection.我对这个问题的基于意见的解决方案是将您需要过滤的收款人信息包含在 Check 集合中。

In my senario, this happen when I was filtering for the sake of my users-roles and permissions, so someone can not see what another one is seeing.在我的 senario 中,当我为了我的用户角色和权限进行过滤时,就会发生这种情况,因此有人看不到另一个人看到的东西。

It's up to you, but this makes it easier later when you want to generate the reports (I assume you're working on a payment service).这取决于你,但这会让你以后生成报告时更容易(我假设你正在处理支付服务)。

The populate() feature provided by mongoose first fetches all the Cheques with given conditions and then makes another query to payee with _id s to populate the fields you wanted. mongoose 提供的populate()功能首先获取所有具有给定条件的Cheques ,然后使用_idpayee进行另一个查询以填充您想要的字段。 https://mongoosejs.com/docs/api.html#query_Query-populate https://mongoosejs.com/docs/api.html#query_Query-populate

by putting match in populate you're filtering which cheques need to be populated but not the cheques themselves.通过将 match 放入 populate 中,您可以过滤需要填充的支票,而不是支票本身。

A simple solution for this is to filter the cheques which are populated as null and return them for your use.一个简单的解决方案是过滤填充为 null 的支票并将它们返回供您使用。

If you see more queries of this sort and/or the collection is huge, it's better you add the payee name in the Cheques collection itself if that fits your purpose.如果您看到更多此类查询和/或集合很大,如果符合您的目的,最好将收款人姓名添加到 Checks 集合本身中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM