【问题标题】:How to find text from populated model in mongoose?如何在猫鼬中从填充模型中查找文本?
【发布时间】:2019-12-20 15:18:40
【问题描述】:

我们有两个模型:

  1. 用户
   const userSchema = new mongoose.Schema({
       name: {
           type: String
       },
       email: {
           type: String
       },
       vehicleId: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'vehicle'
       }
   })
  1. 车辆
    const vehicleSchema = new mongoose.Schema({
       name: {
           type: String
       },
       color: {
           type: String
       }
   })

现在,我们必须从用户(姓名、电子邮件)和车辆(姓名、颜色)中查找用户输入

- If user search "pink" then we have to find that if any user has with name, email or them vehicle include "pink" keyword or not.
- If string match from reference model then we have to return whole record.

你能帮助我们吗,如何实现这一点?

【问题讨论】:

    标签: node.js mongodb mongoose aggregation-framework


    【解决方案1】:

    我认为,你能做的最好的事情就是Text Search

    答案 1:

    1.1。第一步

    您必须在您的集合上创建文本索引才能执行文本搜索。

    创建文本索引

    db.user.createIndex({"name":"text", "email": "text"})
    
    db.vehicle.createIndex({"name": "text", "color": "text"})
    

    我们必须在两个集合上创建文本索引,因为我们想对两个集合执行文本搜索

    * 注意:

    由于我们正在对来自 User 的“name”、“email”和来自 Vehicle 的“name”、“color”创建文本索引,因此您只能对各自集合中的这四个字段执行文本搜索。

    您可以为字段分配权重,以便根据文本分数对结果进行排序。 (您必须在创建索引时执行此操作)。

    *

    1.2。第二步

    (我假设您在这里使用的是 Javascript 和 mongoose。)

     db.collection("users").aggregate({$match:{$text: {$search: "pink"}}},
             (err, userData: any)=>{
                if(err){
                    return err;
                }
    
        if(userdata.length){
    
                let vehicleIds = userData.map((user) => mongoose.Types.ObjectId(user.vehicleId));
    
                db.collection("vehicles").aggregate({$match:{$text:{$search:"pink", _id: {$in: vehicleIds}}}}, (err, vehicleData)=>{
    
                         //this will be your vehicle details
                })
            })
    
       }else{
           console.log("no Data found");
       }
    

    *

    问题使用这种方法时,您必须触发两个查询,因为 文本搜索 中的 restrictions 以及集合上文本索引的额外开销。

    好事是你有很多方法来执行搜索,你可以根据文本分数的相关性对结果进行排序,它比正则表达式快,而且你会得到更好的结果,你会得到词干,你会得到停用词(请参考给出的链接)。 *


    答案 2:

    你可以使用正则表达式

    db.collection("users").aggregate({$match:{$or:[{name:{$regex: /pink/}}, {email:{$regex: /pink/}}]}},
    
        {$lookup:{from:"vehicles", localField:"vehicleId", foreignFild:"_id", as:"vehicleDetail"}},
    
        {$unwind:{path:"$vehicleDetail"}},
    
        {$match:{$or:[{name:{$regex:/pink/}},{color:{$regex:/pink/}}]}}
    
        (err, data)=>{
    
        })
    

    答案 3:

    如果您不想选择上述选项,也可以触发普通查询

    db.collection("users").aggregate({$match:{$or:[{name:{$regex: /pink/}}, {email:{$regex: /pink/}}]} },

        {$lookup:{from:"vehicles", localField:"vehicleId", foreignFild:"_id", as:"vehicleDetail"}},
    
        {$unwind:{path:"$vehicleDetail"}},
    
        {$match:{$or:[{name:{$regex:/pink/}},{color:{$regex:/pink/}}]}}
    
        (err, data)=>{
    
        })
    

    希望这会有所帮助。 :-) 如果我在任何地方错了,请纠正我。 :-)

    【讨论】:

      【解决方案2】:

      您应该遵循以下步骤:

      • 按姓名和电子邮件查找用户。
      • 填充车辆
      • 再次与颜色匹配。

      db.getCollection('User').aggregate([
        { $match: { email: "h@gmail.com", name: "Hardik"}},
        { $lookup: {from: 'Vehicle', localField: 'vehicleId', foreignField: '_id', as: 'vehicle'} },
        { $match: { "vehicle.color": {$regex: '.*'+ "Pink" +'.*', $options: 'si'}}},
      ])
      

      数据:

      用户

      {
          "_id" : ObjectId("5d51bd5ef5fc3d6486b40ffb"),
          "email" : "h@gmail.com",
          "name" : "Hardik",
          "vehicleId" : ObjectId("5d539786f5fc3d6486b4252b")
      }
      

      车辆

      {
          "_id" : ObjectId("5d539786f5fc3d6486b4252b"),
          "name" : "Bike",
          "color" : "Pink"
      }
      

      输出:

      {
          "_id" : ObjectId("5d51bd5ef5fc3d6486b40ffb"),
          "email" : "h@gmail.com",
          "name" : "Hardik",
          "vehicleId" : ObjectId("5d539786f5fc3d6486b4252b"),
          "vehicle" : [ 
              {
                  "_id" : ObjectId("5d539786f5fc3d6486b4252b"),
                  "name" : "Bike",
                  "color" : "Pink"
              }
          ]
      }
      

      希望这会有所帮助!

      【讨论】:

        【解决方案3】:

        您可以首先对 Vehicle 模型运行查询,以获取名称为粉色的所有车辆

        let vehicleIds=await Model.Vehicle.aggregate([
         {$match:{$or:[
                     {name:{$regex:"pink",$options:"i"}},
                     {color:{$regex:"pink",$options:"i"}
         ]}},
         {$group:{_id:null,ids:{$push:"$_id"}}}    
        ])
        

        如果vehicleIds 不为空,则vehicle[0].ids 的vehcileIds 的名称或颜色为粉红色

        let vehcileIds=[]
        if(vehicles.length) vehcileIds=vehicles[0].ids
        

        在上述查询运行后,在用户模型中运行另一个查询

        let users= await Models.User.find({$or:[
        {name:{$regex:"pink",$options:"i"}},
        {email:{$regex:"pink",$options:"i"}
        {vehicleId:{$in:}}
        ]})
        

        【讨论】:

          猜你喜欢
          • 2021-06-29
          • 2021-04-19
          • 2016-04-25
          • 2021-12-25
          • 2015-09-30
          • 1970-01-01
          • 2019-07-17
          • 2021-05-16
          • 2021-04-24
          相关资源
          最近更新 更多