bnomei/kirby-mongodb

Khulan是一个使用MongoDB的NoSQL接口的缓存驱动和内容缓存,适用于Kirby

1.4.4 2024-07-22 13:00 UTC

This package is auto-updated.

Last update: 2024-09-22 14:04:37 UTC


README

Release Downloads Coverage Maintainability Discord

Khulan是一个使用MongoDB的NoSQL接口的缓存驱动和内容缓存,适用于Kirby。

商业用途


支持开源!

此插件免费,但如果您将其用于商业项目,请考虑赞助我或捐款。
如果我的工作帮助您赚了一些钱,那么我认为我可能也应该得到一些回报,对吧?

行善积德。分享一点。谢谢。

—— Bruno
 

安装

  • master.zip解压缩为文件夹site/plugins/kirby-mongodb,或者
  • 使用git submodule add https://github.com/bnomei/kirby-mongodb.git site/plugins/kirby-mongodb,或者
  • 使用composer require bnomei/kirby-mongodb

MongoDB

安装MongoDB有多种方式。以下是在Mac OS X中使用Homebrew和MongoDB Atlas在本地主机上执行此操作的一种方法。

brew install mongodb-atlas
atlas setup # create account and sign-in
atlas deployments setup # -> select localhost
atlas deployments start # start the local mongodb

用例

该插件缓存所有内容文件,并在您添加/删除或更新内容时保持缓存最新。此缓存将在构建页面/文件/用户对象时使用,使所有涉及模型的操作更快(甚至包括面板)。

它还允许您直接将内容缓存作为NoSQL数据库进行查询,这可能对某些用例(如过滤或搜索内容)非常有用。

设置

对于您想要缓存的每个模板,您需要使用一个模型,通过特质添加内容缓存逻辑。

site/models/default.php

class DefaultPage extends \Kirby\Cms\Page
{
    use \Bnomei\ModelWithKhulan;
}

注意

您也可以为用户模型使用特质。文件模型会自动修复。

Kirby的内容进入NoSQL

该插件将内容缓存写入数据库中名为khulan的集合。您可以直接查询此集合。它不是包装在缓存对象中。这允许您将所有Kirby内容视为NoSQL数据库。

// using the collection
$document = khulan()->find(['uuid' => 'XXX']);

// find a single page by uuid string
$page = khulan((string) $myIdOrUUID);

// find a single page by uuid by field-key
$page = khulan(['uuid' => 'page://betterharder']);

// find all pages with a template
$pages = khulan(['template' => 'post']);

// find a user by email or Id
$user = khulan($emailOrId);

// find a file by filename and template
$file = khulan(['filename' => 'my-image.jpg', 'template' => 'image']);

特殊字段:[], {} 和 [,]

插件创建了一些字段类型的修改副本,以便将基于YAML的Kirby内容准备用于查询。您可以使用

  • fieldname[]来查询页面/文件/用户字段中的数组值,以及
  • fieldname{}来查询页面/文件/用户字段中的数组objectId。
  • fieldname[,]来查询逗号分隔的字符串中的字段,如标签/选择/单选框/复选框/多选框字段。
// find all pages that have another page linked
$pages = khulan([
    'related[]' => ['$in' => ['page://fasterstronger']],
]);
$pages = khulan([
    'related{}' => ['$in' => ['dc9f7835c2400cc4']], // objectId
]);

// find all products in the category 'books' or 'movies'
// that had been modified within the last 7 days
$pages = khulan([
    'template' => 'product',
    'category[,]' => ['$in' => ['books', 'movies']],
    'modified' => ['$gt' => time() - (7 * 24 * 60 * 60)]
]);

示例:过滤和解析关系

将Kirby的内容缓存作为NoSQL数据库,您可以进行一些高级过滤。如果您使用Kirby在集合上的过滤来完成相同的工作,您最终会加载很多页面,这并不高效。我们可以直接从缓存中加载所需的信息,而无需加载完整的页面对象。

为什么我们要费心从基于NoSQL的缓存中读取内容,而不是仅仅围绕原生的Kirby逻辑添加缓存?因为缓存的一个难点是知道何时使其无效。使用内容缓存,我们可以直接查询基于NoSQL的缓存,并且更新任何模型都会立即反映出来。而使用围绕原生Kirby逻辑的缓存,我们每次更改都需要重建缓存(如页面缓存)。

假设我们有两个模型:film(电影)和actor(演员)。film模型有一个字段actors,它是一个与actor页面相关联的页面字段。我们想要列出所有电影及其演员。

加载1000部电影及其演员,总共访问了6429个页面,耗时250毫秒。

$films = page('films')->children();
foreach ($films as $film) {
    echo $film->title();
    $actors = [];
    foreach ($film->actors()->toPages() as $actor) {
        $actors[] = $actor->title();
    }
    echo implode(', ', $actors);
}

查询缓存以在100毫秒内获取相同的信息。

/** @var \MongoDB\Driver\Cursor $films */
$films = khulan()->aggregate([
    [
        // only get pages with template 'film'
        '$match' => ['template' => 'film'],
    ],
    [
        // lookup actors by their mongodb objectId
        // this will create an array of objects
        '$lookup' => [
            'from' => 'kirby',
            'localField' => 'actors{}',
            'foreignField' => '_id',
            'as' => 'actor_details',
        ],
    ],
    [
        // only get the fields we need
        // to make the query even faster
        '$project' => [
            'title' => 1,
            'id' => 1,
            'actor_details.title' => 1,
        ],
    ],
]);

/** @var \MongoDB\BSON\Document $film */
foreach ($films as $film) { ?>
<div>
    <a href="<?= url($film->id) ?>"><?= html($film->title) ?></a>
    <ul>
        <?php foreach ($film->actor_details as $actor) { ?>
            <li><?= html($actor->title) ?></li>
        <?php } ?>
    </ul>
</div>
<?php }

注意

此示例来自我的Sakila DB工具包。您可以使用类似的查询来过滤和解析文件和用户对象的关系。

MongoDB客户端

您可以直接访问底层的MongoDB客户端。

/** @var \MongoDB\Client $client */
$client = \Bnomei\Mongodb::singleton()->client();
$client = mongo()->client();

$collection = $client->selectCollection('my-database', 'my-collection');

缓存

您可以直接使用cache,或者将其用作Kirby的cache driver

与默认的基于文件的缓存相比,基于MongoDB的缓存将表现得更差!这是可以预料的,因为Web服务器优化用于处理对数百个文件的请求并保持它们在内存中。

$cache = mongo()->cache();

$cache->set('mykey', 'myvalue', 5); // ttl in minutes
$value = $cache->get('mykey');

$cache->set('tagging', [
    'tags' => ['tag1', 'tag2'],
    'other_value' => 'myothervalue',
]);

与常规的Kirby缓存一样,您也可以使用getOrSet方法将您的耗时代码封装在闭包中,并且只有在缓存为空时才执行它。

$cache = mongo()->cache();

$value = $cache->getOrSet('mykey', function() {
    sleep(5); // like a API call, database query or filtering content
    return 'myvalue';
}, 5); 

使用基于MongoDB的缓存将允许您在缓存上执行NoSQL查询,并执行像过滤我的标签或一次性使多个缓存条目无效这样的高级操作。

// NOTE: we are using the cacheCollection() method here
$collection = mongo()->cacheCollection();

// find all that have the tag 'tag1' and are NOT expired
$documents = $collection->find([
    'value.tags' => ['$in' => ['tag1']],
    'expires_at' => ['$gt' => time()],
]);
foreach ($documents as $document) {
    // $document->value->tags
    // $document->value->other_value
}

// delete any cache entry older than 5 minutes
$deleteResult = $collection->deleteMany([
    'expires_at' => ['$lt' => time() - 5*60]
]);
$deletedCount = $deleteResult->getDeletedCount();

// you can also manually clean expired cache entries
mongo()->clean();

注意

不建议在常规用例中直接查询缓存。它不会检查缓存条目的过期时间并自动删除它们。

在Kirby中使用Cache Driver

您还可以将基于MongoDB的缓存用作Kirby的cache driver。这将允许您用于Kirby中其他扩展的缓存。

site/config/config.php

return [
    // ... other options
    
    // example of using mongodb as cache driver for storing uuids
    // instead of the default file-based cache
    'cache' => [
        'uuid' => [
            'type' => 'mongodb',
        ],
    ],
];

设置

免责声明

此插件提供“现状”,不提供任何保证。请自行承担使用风险,并在将其用于生产环境之前自行测试。如果您发现任何问题,请创建新问题

许可证

MIT

不鼓励在推广种族主义、性别歧视、同性恋恐惧症、动物虐待、暴力或任何其他形式仇恨言论的项目中使用此插件。