【问题标题】:How to Match on Joined Collections Using Laravel and MongoDB?如何使用 Laravel 和 MongoDB 匹配连接的集合?
【发布时间】:2017-11-30 11:08:28
【问题描述】:

我有两个集合“bookings”和“users”。在“预订”集合中,我有一个字段 "user"。它与"users._id" 相关。

我有一个预订列表页面。在此列表页面中显示了来自“预订”和“用户”的数据。

在这个列表页面中,我有一个文本框可以搜索invoice_number, payment_type, txid and usrEmail。我已经写了查询来搜索invoice_number, payment_type, txid,它正在工作,但我被困在usrEmail 部分。如何与users结合并编写搜索查询来搜索usrEmail

我正在使用 laravel 和 mongodb。我在关注“https://github.com/jenssegers/laravel-mongodb

预订

_id, user, invoice_number, payment_type, txid

用户

_id, firstName, SecondName, usrEmail

搜索查询

$bookings = Booking::select('_id', 'invoice_number', 'temp_user_id', 'user', 'checkin_from', 'reserve_to', 'beds', 'dormitory', 'sleeps', 'status', 'payment_status', 'payment_type', 'total_prepayment_amount', 'cabinname', 'reference_no', 'clubmember', 'bookingdate', 'txid')
                ->where('is_delete', 0)
                ->where(function($query) use ($search) { /* That's the closure */
                    $query->where('invoice_number', 'like', "%{$search}%")
                        ->orWhere('payment_type', 'like', "%{$search}%")
                        ->orWhere('txid', 'like', "%{$search}%");
                })
                ->skip($start)
                ->take($limit)
                ->orderBy($order, $dir)
                ->get();

应用\预订

public function user()
    {
        return $this->hasOne('App\Userlist', 'user', '_id');
    }

两个集合的图像 用户 预订

用户收藏

{ "_id" : ObjectId("57877d23049ac1b819000029"), "usrName" : "adminuser", "usrPassword" : "96a65063135247fef732b5901fe05d1f", "usrFirstname" : "Sarath", "usrLastname" : "TS", "usrTelephone" : null, "usrEmail" : "sara@gmail.com", "usrMobile" : "956209959", "usrAddress" : null, "usrFax" : "4564654", "usrZip" : null, "usrBirthday" : null, "usrDAV" : "316148-DAV-Deutscher Alpenverein", "usrActive" : "1", "usrlId" : "1", "lngId" : "1", "usrPasswordSalt" : ";:?hJM\"9=z/)ea?{%-[**:]68UOT>{gj^{P0+RCF#,Id8c:n+h", "usrRegistrationDate" : ISODate("2016-07-14T11:53:07Z"), "usrRegistrationToken" : "2c2e296bda1661c7fc0645f927d0b17f", "is_delete" : "0", "usrUpdateDate" : ISODate("2017-05-16T09:12:07Z"), "usrPasswordDate" : ISODate("2016-10-25T07:35:57Z"), "usrCity" : null, "usrNewsletter" : null, "money_balance" : "0", "usrCountry" : "Deutschland" }

预订集合

{ "_id" : ObjectId("58046a49f8f888a80b00002a"), "cabinname" : "Matras-Haus", "checkin_from" : ISODate("2016-10-17T00:00:00Z"), "reserve_to" : ISODate("2016-10-20T00:00:00Z"), "user" : "57877d23049ac1b819000029", "beds" : "2", "dormitory" : "1", "sleeps" : "3", "clubmember" : "1", "status" : "4", "comments" : "", "bookingdate" : ISODate("2016-10-17T06:06:01Z"), "reservation_cancel" : "2", "is_delete" : NumberLong(1), "payment_status" : "1" }
{ "_id" : ObjectId("58183678d2ae67a404431d5c"), "cabinname" : "Kemptner Hütte", "checkin_from" : ISODate("2016-10-31T23:00:00Z"), "reserve_to" : ISODate("2016-11-23T23:00:00Z"), "user" : "57877d23049ac1b819000029", "beds" : "2", "dormitory" : "0", "sleeps" : "2", "clubmember" : "0", "status" : "1", "total_price" : "1288", "payon_cabin" : "1288", "bed_prefer" : "0", "guests" : "2", "comments" : "", "prepayment_amount" : "0", "bookingdate" : ISODate("2016-11-01T06:30:16Z"), "reservation_cancel" : "2", "is_delete" : NumberLong(1), "payment_status" : "0" }
{ "_id" : ObjectId("581b31f3d2ae674d5f431d5b"), "cabinname" : "Kemptner Hütte", "checkin_from" : ISODate("2016-11-07T23:00:00Z"), "reserve_to" : ISODate("2016-11-17T23:00:00Z"), "user" : "57877d23049ac1b819000029", "beds" : "3", "dormitory" : "0", "sleeps" : "3", "clubmember" : "0", "status" : "1", "total_price" : "840", "payon_cabin" : "840", "bed_prefer" : "0", "guests" : "3", "comments" : "", "prepayment_amount" : "0", "bookingdate" : ISODate("2016-11-03T12:47:47Z"), "reservation_cancel" : "2", "is_delete" : NumberLong(1) }
{ "_id" : ObjectId("5821af65d2ae67c82154efc5"), "cabinname" : "Kemptner Hütte", "checkin_from" : ISODate("2017-09-05T22:00:00Z"), "reserve_to" : ISODate("2018-01-24T23:00:00Z"), "user" : "57877d23049ac1b819000029", "sleeps" : "2", "clubmember" : "0", "status" : "1", "total_price" : "5640", "payon_cabin" : "5630", "bed_prefer" : "0", "guests" : "2", "comments" : "", "prepayment_amount" : "21.25", "bookingdate" : ISODate("2016-11-08T10:56:37Z"), "reservation_cancel" : "2", "is_delete" : NumberLong(1) }
{ "_id" : ObjectId("582558d4d2ae679c4d8b4567"), "cabinname" : "2", "checkin_from" : ISODate("2017-07-31T22:00:00Z"), "reserve_to" : ISODate("2017-08-02T22:00:00Z"), "user" : "57877d23049ac1b819000029", "beds" : "", "dormitory" : "", "sleeps" : "2", "clubmember" : "0", "status" : "", "total_price" : "80", "payon_cabin" : "60", "halfboard" : "", "bed_prefer" : "0", "guests" : "2", "prepayment_amount" : "20", "bookingdate" : ISODate("2016-11-11T05:36:20Z"), "is_delete" : NumberLong(1) }
{ "_id" : ObjectId("58352c3cd2ae672341ec89e1"), "cabinname" : "Kemptner Hütte", "checkin_from" : ISODate("2017-05-31T22:00:00Z"), "reserve_to" : ISODate("2017-06-02T22:00:00Z"), "user" : "57877d23049ac1b819000029", "beds" : "", "dormitory" : "", "sleeps" : "2", "clubmember" : "0", "status" : "", "total_price" : "80", "payon_cabin" : "60", "halfboard" : "", "bed_prefer" : "0", "guests" : "2", "prepayment_amount" : "20", "bookingdate" : ISODate("2016-11-23T05:42:20Z"), "reservation_cancel" : "2", "is_delete" : NumberLong(1) }

【问题讨论】:

    标签: mongodb laravel mongodb-query aggregation-framework


    【解决方案1】:

    您可以使用aggregate() 进行raw 查询,该查询可以使用$lookup 运算符在此处实现“加入”:

      $result = Booking::raw(function($collection) use($search, $start, $limit) {
         return $collection->aggregate(array(
           array( '$lookup' => array(
             'from' => 'users',
             'localField' => 'user',
             'foreignField' => '_id',
             'as' => 'user'
           )),
           array( '$unwind' => array( 
             'path' => '$user', 'preserveNullAndEmptyArrays' => True
           )),
           array( '$match' => array(
             '$or' => array(
               array( 'invoice_number' => array( '$regex' => $search ) ),
               array( 'payment_type' => array( '$regex' => $search ) ),
               array( 'txid' => array( '$regex' => $search ) ),
               array( 'user.usrEmail' => array( '$regex' => $search ) )
             )
           )),
           array( '$skip' => $start ),
           array( '$limit' => $limit )
         ));
      });
    

    $lookup 将为目标字段返回一个“数组”,其中包含“无”或更多与提供的'localField' 值匹配的条目,其中该值可以是单数或值数组。通常我们在这里使用ObjectId,尤其是当链接到'foreignField'_id 时。

    这比任何可以在客户端完成的操作都要好,因为任何其他操作都需要针对每个集合源对数据库进行多次查询。 $lookup 在单个请求和响应中执行此操作。

    唯一真正需要注意的是,由于它与 ORM/ODM “分离”,因此您需要指定实际的“集合名称”,而不是类或模型的名称。所以我在这里只是假设"users",但您可能需要将其调整为您的Users 集合的实际调用。

    无论如何,在您拥有“已加入”数据后,您可以在已加入数据中的 "usrEmail" 属性上 $match,并将其包含在您的查询中。

    至于实际查询,由于您基本上是对来自两个集合的数据执行$or 条件,因此在执行连接“之后”之前,我们无法真正做到$match

    当然还有$skip$limit 的聚合阶段用于您的分页。

    【讨论】:

    • 非常感谢。我已经添加了这个,但我面临一个问题“未知的顶级操作员:$user.usrEmail”。
    • @samsam 错字。对不起。已更正。我有你的意图对吗?您希望在所有这些可能的字段中进行“正则表达式”或 SQL“Like”搜索?
    • 谢谢。目前搜索不适用于 usrEmail。 'localField' => 'user', 'foreignField' => '_id' localfield 表示 bookings.user 正确吗?
    • @samsam 是的。我确实注意到这里的“加入”假设依赖于"localField""foreignField" 彼此相关并且它们必须包含相同的数据类型。因此,如果这是一个 1:1 的关系,那么您需要在“bookings”中存储一些使用来自_id 的值的东西。或者这就是我正在研究的假设。如果预订中的user 实际上是指_id 以外的另一个“外来”字段,则将其指向那里。全部在$lookup 文档中,在答案中链接。
    • @samsam 在你的问题中显示你在做什么。请包括从 mongo shell 中查看的预订和用户的父文档和相关文档。请使用 shell,因为它显示了分配的正确数据类型,而其他转储形式经常会错过。然后我可以清楚地看到您的意见和建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 2017-01-01
    • 2016-05-14
    • 2019-12-27
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多