mongodb 访问
In my previous article Introduction to MongoDB I discussed installing Mongo, its PHP extension, and how to perform simple insert and find operations. Of course there are many, many more features than what I mentioned so I wanted to write another article to show you some of them. In this article you’ll learn about cursors, additional query filters, and running queries on arrays and embedded documents.
在我以前的文章《 MongoDB简介》中,我讨论了如何安装Mongo,其PHP扩展以及如何执行简单的插入和查找操作。 当然,功能比我提到的要多得多,因此我想写另一篇文章向您展示其中的一些功能。 在本文中,您将了解游标,其他查询过滤器以及在数组和嵌入式文档上运行查询。
游标 (Cursors)
First let’s talk about cursors in MongoDB. In the earlier article you saw an example of a find operation like the one below, which selects all the documents found in a collection matching the passed criteria:
首先让我们讨论一下MongoDB中的游标。 在较早的文章中,您看到了一个类似于以下操作的查找操作示例,该操作选择了在集合中找到的所有符合通过条件的文档:
<?php
$cursor = $collection->find(array("author" => "shreef"));
What I only briefly mentioned at the time was the find()
method returns a MongoCursor
instance (not a list of the actual documents found). Nothing is requested from MongoDB until you call for a result from the cursor.
当时我仅简要提到的是find()
方法返回一个MongoCursor
实例(而不是找到的实际文档的列表)。 除非您从游标中调用结果,否则MongoDB不会请求任何内容。
Mongo’s cursor has two life stages. The first stage is the “pre-query stage.” At this point, the cursor hasn’t tried to execute the query and you have a chance to add more details and constraints. For example, if you want to specify the maximum number of documents to be returned, you can use the cursor’s limit()
method.
Mongo的光标具有两个生命阶段。 第一阶段是“预查询阶段”。 此时,游标尚未尝试执行查询,您有机会添加更多详细信息和约束。 例如,如果要指定要返回的最大文档数,则可以使用游标的limit()
方法。
<?php
$cursor = $collection->find(array("author" => "shreef"));
$cursor = $cursor->limit(5);
Oftentimes you’ll see the method invocations chained together like so:
通常,您会看到方法调用链接在一起,如下所示:
<?php
$cursor = $collection->find(array("author" => "shreef"))->limit(5);
The cursor actually performs the query and moves to its second stage, the “post-query stage,” once you try to read the results from the cursor either by calling the next()
method directly or by iterating the cursor:
一旦尝试通过直接调用next()
方法或迭代游标从游标中读取结果,游标实际上就会执行查询并进入第二阶段,即“查询后阶段”。
<?php
foreach ($cursor as $doc) {
// do something
}
Also worth mentioning is that not all of the documents matching the criteria of your query will be returned at the same time. If the total size of the results is large, you probably wouldn’t want to load all that data into memory anyway. MonogDB has a limit of 4-16MB worth of returned results. When you’ve finished iterating through the first batch of results, the cursor will transparently retrieve the next batch of documents. All of this happens in the background for you so you don’t have to worry about it while writing your code, but it’s worth mentioning so you know what is actually happening.
还值得一提的是,并非所有与查询条件匹配的文档都会同时返回。 如果结果的总大小很大,那么您可能根本不想将所有数据加载到内存中。 MonogDB返回的结果限制为4-16MB。 完成对第一批结果的迭代之后,光标将透明地检索下一批文档。 所有这些都在您的后台发生,因此您在编写代码时不必担心它,但是值得一提,这样您就可以知道实际发生的情况。
By default, MongoDB will keep the cursor alive on the server until either you’ve finished reading all the results assigned to it, or 10 minutes have passed since its creation. You can use MongoCursor
‘s timeout()
method to increase or decrease the life of the cursor (in milliseconds). You can also pass -1 to timeout()
to disable the timeout behavior, but then you’ll have to iterate over all of the results or else the cursor will live forever and exhaust the resources of the server.
默认情况下,MongoDB将使游标在服务器上保持活动状态,直到您完成读取分配给它的所有结果,或者自创建以来已过10分钟。 您可以使用MongoCursor
的timeout()
方法来增加或减少游标的寿命(以毫秒为单位)。 您还可以将-1传递给timeout()
以禁用超时行为,但是随后您必须遍历所有结果,否则游标将永久存在并耗尽服务器资源。
查询运算符 (Query Operators)
Queries in MongoDB are simple to grasp after seeing only a few examples. You’ve seen that you can send the query as an array containing the values to be matched and you can fine-tune your matching criteria using the special $
-operators supported by MongoDB. I’d like to show you the operators used for logical comparisons now, but first there’s one important note: always remember to use single quotes with the $
-operators or escape them. You can probably guess why.
仅查看几个示例即可轻松掌握MongoDB中的查询。 您已经看到,您可以将查询作为包含要匹配的值的数组发送,并且可以使用MongoDB支持的特殊$
运算符微调匹配条件。 我现在想向您展示用于逻辑比较的运算符,但首先要注意一个重要事项:始终记住在$
运算符中使用单引号或将其转义。 您可能会猜出原因。
$ lt,$ lte,$ gt,$ gte ($lt, $lte, $gt, $gte)
The $lt
, $lte
, $gt
, and $gte
operators are equivalent to <
, <=
, >
, and >=
. To find all the documents in a blog collection with a number of views greater than or equal to 50,000, you would construct a query like this:
$lt
, $lte
, $gt
和$gte
运算符等效于<
, <=
, >
和>=
。 要在博客集中查找所有视图的视图大于或等于50,000,请构造如下查询:
<?php
$collection->find(array("views" => array('$gte' => 50000)));
views
is the name of the field that should contain a value greater than or equal 50,000.
views
是字段名称,其值应大于或等于50,000。
$ and,$ or和$ nor ($and, $or, and $nor)
Sometimes you’ll want to make sure a value fulfills more than one condition, or at lest one of several conditions. The $and
and $or
operators are used to provide Boolean conditions, the same as you are already used to. If you want to find all blog posts with a number of views greater or equal to 50,000 authored by either “Shreef” or “Timothy”, you would write a query like this:
有时,您需要确保一个值满足多个条件,或者至少满足多个条件之一。 $and
$or
运算符用于提供布尔条件,与您已经习惯的条件相同。 如果要查找所有由“ Shreef”或“ Timothy”撰写的视图数大于或等于50,000的博客文章,则可以编写如下查询:
<?php
$collection->find(array(
"views" => array('$gte' => 50000),
"$or" => array(
array("author" => "Shreef"),
array("author" => "Timothy"))));
The $nor
operator is used similarly, but ensures that none of the conditions are met.
$nor
运算符的用法类似,但是确保不满足任何条件。
$ in和$ nin(不在) ($in and $nin (not in))
The $in
operator is useful when you want to pass a list of values that one of them should match the field you are checking. The $nin
operator does the opposite, checking that the field doesn’t match any of the values. This can oftentimes be more readable than using the previously mentioned Boolean operators when you’re doing a simple query.
当您要传递一个值列表,其中一个值应与您要检查的字段匹配时, $in
运算符很有用。 $nin
运算符执行相反的操作,检查该字段与任何值都不匹配。 在执行简单查询时,这通常比使用前面提到的布尔运算符更具可读性。
<?php
$collection->find(array(
"authors" => array('$in' => array("Shreef", "Timothy"))));
数组查询 (Queries on Arrays)
The previous examples demonstrated the ability to create and query fields containing a single value, but MongoDB supports array values as well. To provide a list of tags that organizes the blog posts, for example, you can simply specify them as an array.
前面的示例演示了创建和查询包含单个值的字段的能力,但是MongoDB也支持数组值。 例如,要提供用于组织博客文章的标签列表,只需将它们指定为数组即可。
<?php
$collection->insert(array(
"title" => "More Mongo",
"author" => "Shreef",
"tags" => array("php", "mongodb")));
Now to find documents tagged with “php” you can do the following:
现在要查找标记有“ php”的文档,您可以执行以下操作:
<?php
$collection->find(array("tags" => "php"));
Querying an array is the same as querying a field with a single value, and any array that lists “php” as one of its tag values will match. You can also use all the previously mentioned $
-operators with arrays, plus the $all
operator which allows you to check an array contains all of the the values passed.
查询数组与查询具有单个值的字段相同,并且任何将“ php”作为其标记值之一列出的数组都将匹配。 您还可以使用前面提到的所有$
-operators使用数组,加上$all
运营商允许你检查数组包含了所有传递的价值观。
<?php
$collection->find(array(
"tags" => array('$all' => array("php", "mongodb")));
Now with $all
, this query will only match documents with the tags “php” and “mongodb”. Having just one of these values won’t be enough to match.
现在使用$all
,此查询将仅匹配带有标签“ php”和“ mongodb”的文档。 仅拥有这些值之一是不够的。
嵌入式文档查询 (Queries on Embedded Documents)
Embedding documents is one of the things that you’ll probably deal with a lot if you’re using MongoDB for any serious application. For example, it might be logical to embed all of the comments on a post inside the same blog post document. Let’s assume Sophia added a new comment; you might update your blog document by pushing her comment to the comments array like so:
如果将MongoDB用于任何严肃的应用程序,则嵌入文档是您可能要处理的很多事情之一。 例如,将所有评论嵌入同一博客文章文档中的文章可能是合乎逻辑的。 假设Sophia添加了新评论; 您可以通过如下方式将博客文档的评论推送到comments数组来更新您的博客文档:
<?php
$postId = "xxx";
$collection->update(
array("_id" => new Mongo($postId)),
array('$push' => array(
"comments" => array(
"author" => "Sophia",
"content" => "hi..."))));
As you saw, I used an operator called $push
which, from its name you can probably guess, pushes a new item onto an array. Performance-wise this approach is better than loading the entire document from the database, modifying it, and then writing it back to the database.
如您所见,我使用了一个名为$push
的运算符,您可能会猜到它的名称,它将一个新项推入数组。 从性能角度来看,此方法比从数据库加载整个文档,对其进行修改然后再将其写回到数据库更好。
Now when you want to retrieve all of the comments made by Sophia, you can query for them like this:
现在,当您要检索Sophia的所有评论时,可以像这样查询它们:
<?php
$collection->find(array("comments.author" => "Sophia"));
You can write field names like this since MongoDB supports dot notation. Dot notation lets you write the names of fields as if they were object properties; by writing “comments.author” I can reference the value of the author
field that exists in the comments
object.
您可以这样写字段名称,因为MongoDB支持点表示法。 点符号使您可以将字段名称写为对象属性。 通过编写“ comments.author”,我可以引用comments
对象中存在的author
字段的值。
sort()和skip()方法 (The sort() and skip() Methods)
I’ve already mentioned the limit()
method which accepts a count of documents to return when you do a query. MongoCursor offers other other methods that you’ll undoubtedly find useful, such as sort()
and skip()
.
我已经提到了limit()
方法,该方法接受查询时要返回的文档数量。 MongoCursor还提供了其他无疑有用的其他方法,例如sort()
和skip()
。
The sort()
method is like the ORDER BY
clause in SQL – you provide a number of fields to be used for sorting the results and specify how each is sorted. 1 represents ascending and -1 represents descending.
sort()
方法类似于SQL中的ORDER BY
子句–您提供了许多用于对结果进行排序的字段,并指定了如何对每个结果进行排序。 1代表升序,-1代表降序。
<?php
$collection
->find()
->sort(array("createdAt" => -1 , "author" => 1));
This will sort the matching documents by their creation date in descending order first, then by their author in ascending order.
这将按照它们的创建日期先按降序对匹配的文档进行排序,然后按其作者按升序对它们进行排序。
The skip()
method passes over the provided number of documents that match the query. For example:
skip()
方法会skip()
提供的与查询匹配的文档数量。 例如:
<?php
$collection
->find(array("author" => "Shreef"))
->sort(array("createdAt" => -1))
->limit(5)
->skip(10);
The query searches for all documents authored by Shreef, ordered by their creation time, and then skips the first 10 documents that would have otherwise been returned to instead return the next 5 documents only.
该查询搜索Shreef创作的所有文档(按其创建时间排序),然后跳过本应返回的前10个文档,而仅返回接下来的5个文档。
Sorting documents leads to a very important point: indexing in MongoDB is just as important as in a RDBMS such as MySQL.
对文档进行排序会导致非常重要的一点:在MongoDB中建立索引与在MySQL等RDBMS中一样重要。
指标 (Indexes)
Running queries without indexes doesn’t make much sense in any database. You have to create indexes on the fields that you’ll be referencing in your queries, including those you’ll use for sorting. You can create an index in MongoDB using the ensureIndex()
method. The method accepts a list of fields as the first argument and an optional list of options as the second. Here’s an example:
在没有索引的情况下运行查询没有任何意义。 您必须在查询中要引用的字段上创建索引,包括用于排序的字段。 您可以使用ensureIndex()
方法在MongoDB中创建索引。 该方法接受字段列表作为第一个参数,并接受选项的可选列表作为第二个参数。 这是一个例子:
<?php
$collection->ensureIndex(
array("author" => 1),
array("name" => "idx_author"));
This will create an ascending index using the author
field and I optionally chose to name the index “idx_author”. You can create an index with multiple fields by adding the names of the fields as keys to the array passed in the first argument and set their values o either 1 or -1. Using 1 means you want the indexing of the field to be ascending, while using -1 means you want it to be descending.
这将使用author
字段创建一个升序索引,我可以选择将索引命名为“ idx_author”。 您可以通过将字段名称作为键添加到第一个参数中传递的数组并将字段的值设置为1或-1来创建具有多个字段的索引。 使用1表示您希望字段的索引递增,而使用-1表示您希望字段的索引递减。
Other options you may need are the unique
and dropDups
options. You can create an index to ensure a field is unique across all documents in the collection by setting unique
to “true”. If you set dropDups
true, MongoDB will drop all duplicates except only one.
您可能需要的其他选项是unique
和dropDups
选项。 您可以通过将unique
设置为“ true”来创建索引,以确保字段在集合中的所有文档中都是唯一的。 如果将dropDups
设置dropDups
true,则MongoDB将删除所有重复项,只有一个除外。
<?php
$collection->ensureIndex(
array("title" => 1),
array("unique" => true, "dropDups" => true));
MongoDB tries to guess the best index to use when executing your query, but sometimes it fails to choose the right one. You use the hint()
method to tell it about the fields to use.
MongoDB尝试猜测执行查询时要使用的最佳索引,但是有时它无法选择正确的索引。 您可以使用hint()
方法来告知要使用的字段。
<?php
$collection
->find(array("author" => "shreef"))
->hint(array("author" => 1));
In this example I told Mongo to use the index consisting of the author
field that’s sorted in ascending order. You must pass the same criteria you used to create the index and in the same order. If there is no index consisting of the passed fields in the same order, an exception will be thrown.
在此示例中,我告诉Mongo使用由author
字段组成的索引,该author
字段按升序排序。 您必须以相同的顺序传递用于创建索引的相同条件。 如果没有按相同顺序包含传递字段的索引,则将引发异常。
You might be wondering why you can’t just use the name of the index instead. Actually, this is supported by Mongo, but it looks like it wasn’t implemented in the PHP API. The hint()
method in the PHP API only accepts an array. Let’s hope this will be fixed soon!
您可能想知道为什么不能只使用索引名称。 实际上,Mongo对此提供了支持,但是它似乎没有在PHP API中实现。 PHP API中的hint()
方法仅接受一个数组。 希望这个问题能尽快解决!
摘要 (Summary)
MongoDB is getting better with every release and there are still many more features that I didn’t mention here. The PHP manual gives you some information, but it’s best to read the MongoDB documentation to learn about the latest and greatest features. This article is full of things that you can try, like using $
-operators, querying embedded documents, and sorting and skipping results. Feel free to tinker with them and leave your questions and your findings in the comments.
MongoDB的每个发行版都在不断完善,还有许多我没有在这里提到的功能。 PHP手册为您提供了一些信息,但是最好阅读MongoDB文档以了解最新和最出色的功能。 本文包含您可以尝试的所有内容,例如使用$
-operators,查询嵌入式文档以及对结果进行排序和跳过。 随时修改它们,并在评论中留下您的问题和发现。
Image via Pakhnyushcha / Shutterstock
图片来自Pakhnyushcha / Shutterstock
mongodb 访问