摘要:上一篇文章指南簡介下一篇文章指南基礎(chǔ)知識數(shù)據(jù)類型非常強(qiáng)大但很容易上手。把同種類型的文檔放在一個集合里,數(shù)據(jù)會更加集中。命名集合使用名稱進(jìn)行標(biāo)識。集合名不能是空字符串。簡單起見,數(shù)據(jù)庫名應(yīng)全部小寫。
</>復(fù)制代碼
上一篇文章:MongoDB指南---1、MongoDB簡介
下一篇文章:MongoDB指南---3、MongoDB基礎(chǔ)知識-數(shù)據(jù)類型
MongoDB非常強(qiáng)大但很容易上手。本章會介紹一些MongoDB的基本概念。
文檔是MongoDB中數(shù)據(jù)的基本單元,非常類似于關(guān)系型數(shù)據(jù)庫管理系統(tǒng)中的行,但更具表現(xiàn)力。
類似地,集合(collection)可以看作是一個擁有動態(tài)模式(dynamic schema)的表。
MongoDB的一個實例可以擁有多個相互獨立的數(shù)據(jù)庫(database),每一個數(shù)據(jù)庫都擁有自己的集合。
每一個文檔都有一個特殊的鍵"_id", 這個鍵在文檔所屬的集合中是唯一的。
MongoDB自帶了一個簡單但功能強(qiáng)大的JavaScript shell,可用于管理MongoDB的實例或數(shù)據(jù)操作。
文檔是MongoDB的核心概念。文檔就是鍵值對的一個有序集。每種編程語言表示文檔的方法不太一樣,但大多數(shù)編程語言都有一些相通的數(shù)據(jù)結(jié)構(gòu),比如映射(map)、散列(hash)或字典(dictionary)。例如,在JavaScript 里面,文檔被表示為對象:
</>復(fù)制代碼
{"greeting" : "Hello, world!"}
這個文檔只有一個鍵"greeting",其對應(yīng)的值為"Hello,world!"。大多數(shù)文檔會比這個簡單的例子復(fù)雜得多,通常會包含多個鍵/值對:
</>復(fù)制代碼
{"greeting" : "Hello, world!", "foo" : 3}
從上面的例子可以看出,文檔中的值可以是多種不同的數(shù)據(jù)類型(甚至可以是一個完整的內(nèi)嵌文檔,詳見2.6.4節(jié))。在這個例子中,"greeting"的值是一個字符串,而"foo"的值是一個整數(shù)。
文檔的鍵是字符串。除了少數(shù)例外情況,鍵可以使用任意UTF-8字符。
鍵不能含有0(空字符)。這個字符用于表示鍵的結(jié)尾。
.和$具有特殊意義,只能在特定環(huán)境下使用(后面的章節(jié)會詳細(xì)說明)。通常,這兩個字符是被保留的;如果使用不當(dāng)?shù)脑挘?qū)動程序會有提示。
MongoDB不但區(qū)分類型,而且區(qū)分大小寫。例如,下面的兩個文檔是不同的:
</>復(fù)制代碼
{"foo" : 3}
{"foo" : "3"}
下面兩個文檔也是不同的:
</>復(fù)制代碼
{"foo" : 3}
{"Foo" : 3}
還有一個非常重要的事項需要注意,MongoDB的文檔不能有重復(fù)的鍵。例如,下面的文檔是非法的:
</>復(fù)制代碼
{"greeting" : "Hello, world!", "greeting" : "Hello, MongoDB!"}
文檔中的鍵/值對是有序的:{"x" : 1, "y":2}與{"y": 2, "x": 1}是不同的。通常,字段順序并不重要,無須讓數(shù)據(jù)庫模式依賴特定的字段順序(MongoDB會對字段重新排序)。在某些特殊情況下,字段順序變得非常重要,本書將就此給出提示。
一些編程語言對文檔的默認(rèn)表示根本就不包含順序問題(如:Python中的字典、Perl和Ruby 1.8中的散列)。通常,這些語言的驅(qū)動具有某些特殊的機(jī)制,可以在必要時指定文檔的順序。
集合就是一組文檔。如果將MongoDB中的一個文檔比喻為關(guān)系型數(shù)據(jù)庫中的一行,那么一個集合就相當(dāng)于一張表。
2.2.1 動態(tài)模式集合是動態(tài)模式的。這意味著一個集合里面的文檔可以是各式各樣的。例如,下面兩個文檔可以存儲在同一個集合里面:
</>復(fù)制代碼
{"greeting" : "Hello, world!"}
{"foo" : 5}
需要注意的是,上面的文檔不光值的類型不同(一個是字符串,一個是整數(shù)),它們的鍵也完全不同。因為集合里面可以放置任何文檔,隨之而來的一個問題是:還有必要使用多個集合嗎?這的確值得思考:既然沒有必要區(qū)分不同類型文檔的模式,為什么還要使用多個集合呢?這里有幾個重要的原因。
如果把各種各樣的文檔不加區(qū)分地放在同一個集合里,無論對開發(fā)者還是對管理員來說都將是噩夢。開發(fā)者要么確保每次查詢只返回特定類型的文檔,要么讓執(zhí)行查詢的應(yīng)用程序來處理所有不同類型的文檔。如果查詢博客文章時還要剔除含有作者數(shù)據(jù)的文檔,這會帶來很大困擾。
在一個集合里查詢特定類型的文檔在速度上也很不劃算,分開查詢多個集合要快得多。例如,假設(shè)集合里面一個名為"type"的字段用于指明文檔是skim、whole還是chunky monkey。那么,如果從一個集合中查詢這三種類型的文檔,速度會很慢。但如果將這三種不同類型的文檔拆分為三個不同的集合,每次只需要查詢相應(yīng)的集合,速度快得多。
把同種類型的文檔放在一個集合里,數(shù)據(jù)會更加集中。從一個只包含博客文章的集合里查詢幾篇文章,或者從同時包含文章數(shù)據(jù)和作者數(shù)據(jù)的集合里查出幾篇文章,相比之下,前者需要的磁盤尋道操作更少。
創(chuàng)建索引時,需要使用文檔的附加結(jié)構(gòu)(特別是創(chuàng)建唯一索引時)。索引是按照集合來定義的。在一個集合中只放入一種類型的文檔,可以更有效地對集合進(jìn)行索引。
上面這些重要原因促使我們創(chuàng)建一個模式,把相關(guān)類型的文檔組織在一起,盡管MongoDB對此并沒有強(qiáng)制要求。
集合使用名稱進(jìn)行標(biāo)識。集合名可以是滿足下列條件的任意UTF-8字符串。
集合名不能是空字符串("")。
集合名不能包含0字符(空字符),這個字符表示集合名的結(jié)束。
集合名不能以“system.”開頭,這是為系統(tǒng)集合保留的前綴。例如,system.users這個集 合保存著數(shù)據(jù)庫的用戶信息,而system.namespaces集合保存著所有數(shù)據(jù)庫集合的信息。
用戶創(chuàng)建的集合不能在集合名中包含保留字符"$"。因為某些系統(tǒng)生成的集合中包含$,很多驅(qū)動程序確實支持在集合名里包含該字符。除非你要訪問這種系統(tǒng)創(chuàng)建的集合,否則不應(yīng)該在集合名中包含$。
子集合組織集合的一種慣例是使用“.”分隔不同命名空間的子集合。例如,一個具有博客功能的應(yīng)用可能包含兩個集合,分別是blog.posts和blog.authors。這是為了使組織結(jié)構(gòu)更清晰,這里的blog集合(這個集合甚至不需要存在)跟它的子集合沒有任何關(guān)系。
雖然子集合沒有任何特別的屬性,但它們卻非常有用,因而很多MongoDB工具都使用了子集合。
GridFS(一種用于存儲大文件的協(xié)議)使用子集合來存儲文件的元數(shù)據(jù),這樣就可以與文件內(nèi)容塊很好地隔離開來。(第6章會詳細(xì)介紹GridFS。)
大多數(shù)驅(qū)動程序都提供了一些語法糖,用于訪問指定集合的子集合。例如,在數(shù)據(jù)庫shell中,db.blog代表blog集合,而db.blog.posts代表blog.posts集合。
在MongoDB中,使用子集合來組織數(shù)據(jù)非常高效,值得推薦。
2.3 數(shù)據(jù)庫在MongoDB中,多個文檔組成集合,而多個集合可以組成數(shù)據(jù)庫。一個MongoDB實例可以承載多個數(shù)據(jù)庫,每個數(shù)據(jù)庫擁有0個或者多個集合。每個數(shù)據(jù)庫都有獨立的權(quán)限,即便是在磁盤上,不同的數(shù)據(jù)庫也放置在不同的文件中。按照經(jīng)驗,我們將有關(guān)一個應(yīng)用程序的所有數(shù)據(jù)都存儲在同一個數(shù)據(jù)庫中。要想在同一個MongoDB服務(wù)器上存放多個應(yīng)用程序或者用戶的數(shù)據(jù),就需要使用不同的數(shù)據(jù)庫。
數(shù)據(jù)庫通過名稱來標(biāo)識,這點與集合類似。數(shù)據(jù)庫名可以是滿足以下條件的任意UTF-8字符串。
不能是空字符串("")。
不得含有/、、.、"、*、<、>、:、|、?、$(一個空格)、0(空字符)。基本上,只能使用ASCII中的字母和數(shù)字。
數(shù)據(jù)庫名區(qū)分大小寫,即便是在不區(qū)分大小寫的文件系統(tǒng)中也是如此。簡單起見,數(shù)據(jù)庫名應(yīng)全部小寫。
數(shù)據(jù)庫名最多為64字節(jié)。
要記住一點,數(shù)據(jù)庫最終會變成文件系統(tǒng)里的文件,而數(shù)據(jù)庫名就是相應(yīng)的文件名,這是數(shù)據(jù)庫名有如此多限制的原因。
另外,有一些數(shù)據(jù)庫名是保留的,可以直接訪問這些有特殊語義的數(shù)據(jù)庫。這些數(shù)據(jù)庫如下所示。
admin
從身份驗證的角度來講,這是“root”數(shù)據(jù)庫。如果將一個用戶添加到admin數(shù)據(jù)庫,這個用戶將自動獲得所有數(shù)據(jù)庫的權(quán)限。再者,一些特定的服務(wù)器端命令也只能從admin數(shù)據(jù)庫運行,如列出所有數(shù)據(jù)庫或關(guān)閉服務(wù)器。
local
這個數(shù)據(jù)庫永遠(yuǎn)都不可以復(fù)制,且一臺服務(wù)器上的所有本地集合都可以存儲在這個數(shù)據(jù)庫中。(第9章會詳細(xì)介紹復(fù)制及本地數(shù)據(jù)庫。)
config
MongoDB用于分片設(shè)置時(參見第13章),分片信息會存儲在config數(shù)據(jù)庫中。
把數(shù)據(jù)庫名添加到集合名前,得到集合的完全限定名,即命名空間(namespace)。例如,如果要使用cms數(shù)據(jù)庫中的blog.posts集合,這個集合的命名空間就是cms.blog.posts。命名空間的長度不得超過121字節(jié),且在實際使用中應(yīng)小于100字節(jié)。(參考附錄B,了解MongoDB中集合的命名空間及內(nèi)部表示的更多信息。)
2.4 啟動MongoDB通常,MongoDB作為網(wǎng)絡(luò)服務(wù)器來運行,客戶端可連接到該服務(wù)器并執(zhí)行操作。下載MongoDB(http://www.mongodb.org/downloads)并解壓,運行mongod命令,啟動數(shù)據(jù)庫服務(wù)器:
</>復(fù)制代碼
$ mongod
mongod --help for help and startup options
Thu Oct 11 12:36:48 [initandlisten] MongoDB starting : pid=2425 port=27017
dbpath=/data/db/ 64-bit host=spock
Thu Oct 11 12:36:48 [initandlisten] db version v2.4.0, pdfile version 4.5
Thu Oct 11 12:36:48 [initandlisten] git version:
3aaea5262d761e0bb6bfef5351cfbfca7af06ec2
Thu Oct 11 12:36:48 [initandlisten] build info: Darwin spock 11.2.0 Darwin Kernel
Version 11.2.0: Tue Aug 9 20:54:00 PDT 2011;
root:xnu-1699.24.8~1/RELEASE_X86_64 x86_64 BOOST_LIB_VERSION=1_48
Thu Oct 11 12:36:48 [initandlisten] options: {}
Thu Oct 11 12:36:48 [initandlisten] journal dir=/data/db/journal
Thu Oct 11 12:36:48 [initandlisten] recover : no journal files present, no
recovery needed
Thu Oct 11 12:36:48 [websvr] admin web console waiting for connections on
port 28017
Thu Oct 11 12:36:48 [initandlisten] waiting for connections on port 27017
在Windows系統(tǒng)中,執(zhí)行這個命令:
</>復(fù)制代碼
$ mongod.exe
mongod在沒有參數(shù)的情況下會使用默認(rèn)數(shù)據(jù)目錄/data/db(Windows系統(tǒng)中為C:datadb)。如果數(shù)據(jù)目錄不存在或者不可寫,服務(wù)器會啟動失敗。因此,在啟動MongoDB前,先創(chuàng)建數(shù)據(jù)目錄(如mkdir -p /data/db/),以確保對該目錄有寫權(quán)限,這點非常重要。
</>復(fù)制代碼
sudo mkdir -p /data/db/
sudo chmod -R 777 /data/db
啟動時,服務(wù)器會打印版本和系統(tǒng)信息,然后等待連接。默認(rèn)情況下,MongoDB監(jiān)聽27017端口。如果端口被占用,啟動將失敗。通常,這是由于已經(jīng)有一個MongoDB實例在運行了。
mongod還會啟動一個非常基本的HTTP服務(wù)器,監(jiān)聽數(shù)字比主端口號高1000的端口,也就是28017端口。這意味著,通過瀏覽器訪問http://localhost:28017,能獲取數(shù)據(jù)庫的管理信息。
中止mongod的運行,只須在運行著服務(wù)器的shell中按下Ctrl-C。
MongoDB自帶JavaScript shell,可在shell中使用命令行與MongoDB實例交互。shell非常有用,通過它可以執(zhí)行管理操作,檢查運行實例,亦或做其他嘗試。對MongoDB來說,mongo shell是至關(guān)重要的工具,其應(yīng)用之廣泛將體現(xiàn)在本書接下來的部分中。
2.5.1 運行shell運行mongo啟動shell:
</>復(fù)制代碼
$ mongo
MongoDB shell version: 2.4.0
connecting to: test
啟動時,shell將自動連接MongoDB服務(wù)器,須確保mongod已啟動。
shell是一個功能完備的JavaScript解釋器,可運行任意JavaScript程序。為說明這一點,我們運行幾個簡單的數(shù)學(xué)運算:
</>復(fù)制代碼
> x = 200
200
> x / 5;
40
另外,可充分利用JavaScript的標(biāo)準(zhǔn)庫:
</>復(fù)制代碼
> Math.sin(Math.PI / 2);
1
> new Date("2010/1/1");
"Fri Jan 01 2010 00:00:00 GMT-0500 (EST)"
> "Hello, World!".replace("World", "MongoDB");
Hello, MongoDB!
再者,可定義和調(diào)用JavaScript函數(shù):
> function factorial (n) {
... if (n <= 1) return 1;
... return n * factorial(n - 1);
... }
> factorial(5);
120
需要注意,可使用多行命令。shell會檢測輸入的JavaScript語句是否完整,如沒寫完可在下一行接著寫。在某行連續(xù)三次按下回車鍵可取消未輸入完成的命令,并退回到>-提示符。
2.5.2 MongoDB客戶端能運行任意JavaScript程序聽上去很酷,不過shell的真正強(qiáng)大之處在于,它是一個獨立的MongoDB客戶端。啟動時,shell會連到MongoDB服務(wù)器的test數(shù)據(jù)庫,并將數(shù)據(jù)庫連接賦值給全局變量db。這個變量是通過shell訪問MongoDB的主要入口點。
如果想要查看db當(dāng)前指向哪個數(shù)據(jù)庫,可以使用db命令:
</>復(fù)制代碼
> db
test
為了方便習(xí)慣使用SQL shell的用戶,shell還包含一些非JavaScript語法的擴(kuò)展。這些擴(kuò)展并不提供額外的功能,而是一些非常棒的語法糖。例如,最重要的操作之一為選擇數(shù)據(jù)庫:
</>復(fù)制代碼
> use foobar
switched to db foobar
現(xiàn)在,如果查看db變量,會發(fā)現(xiàn)其正指向foobar數(shù)據(jù)庫:
</>復(fù)制代碼
> db
foobar
因為這是一個JavaScript shell,所以鍵入一個變量會將此變量的值轉(zhuǎn)換為字符串(即數(shù)據(jù)庫名)并打印出來。
通過db變量,可訪問其中的集合。例如,通過db.baz可返回當(dāng)前數(shù)據(jù)庫的baz集合。因為通過shell可訪問集合,這意味著,幾乎所有數(shù)據(jù)庫操作都可以通過shell完成。
在shell中查看或操作數(shù)據(jù)會用到4個基本操作:創(chuàng)建、讀取、更新和刪除(即通常所說的CRUD操作)。
1. 創(chuàng)建insert函數(shù)可將一個文檔添加到集合中。舉一個存儲博客文章的例子。首先,創(chuàng)建一個名為post的局部變量,這是一個JavaScript對象,用于表示我們的文檔。它會有幾個鍵:"title"、"content"和"date"(發(fā)布日期)。
</>復(fù)制代碼
> post = {"title" : "My Blog Post",
... "content" : "Here"s my blog post.",
... "date" : new Date()}
{
"title" : "My Blog Post",
"content" : "Here"s my blog post.",
"date" : ISODate("2012-08-24T21:12:09.982Z")
}
這個對象是個有效的MongoDB文檔,所以可以用insert方法將其保存到blog集合中:
</>復(fù)制代碼
> db.blog.insert(post)
這篇文章已被存到數(shù)據(jù)庫中。要查看它可用調(diào)用集合的find方法:
</>復(fù)制代碼
> db.blog.find()
{
"_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
"title" : "My Blog Post",
"content" : "Here"s my blog post.",
"date" : ISODate("2012-08-24T21:12:09.982Z")
}
可以看到,我們曾輸入的鍵/值對都已被完整地記錄。此外,還有一個額外添加的鍵"_id"。"_id"突然出現(xiàn)的原因?qū)⒃诒菊履┪步忉尅?/p> 2. 讀取
find和findOne方法可以用于查詢集合里的文檔。若只想查看一個文檔,可用findOne:
</>復(fù)制代碼
> db.blog.findOne()
{
"_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
"title" : "My Blog Post",
"content" : "Here"s my blog post.",
"date" : ISODate("2012-08-24T21:12:09.982Z")
}
find和findOne可以接受一個查詢文檔作為限定條件。這樣就可以查詢符合一定條件的文檔。使用find時,shell會自動顯示最多20個匹配的文檔,也可獲取更多文檔。第4章會詳細(xì)介紹查詢相關(guān)的內(nèi)容。
3. 更新使用update修改博客文章。update接受(至少)兩個參數(shù):第一個是限定條件(用于匹配待更新的文檔),第二個是新的文檔。假設(shè)我們要為先前寫的文章增加評論功能,就需要增加一個新的鍵,用于保存評論數(shù)組。
首先,修改變量post,增加"comments"鍵:
</>復(fù)制代碼
> post.comments = []
[ ]
然后執(zhí)行update操作,用新版本的文檔替換標(biāo)題為“My Blog Post”的文章:
</>復(fù)制代碼
> db.blog.update({title : "My Blog Post"}, post)
現(xiàn)在,文檔已經(jīng)有了"comments"鍵。再用find查看一下,可以看到新的鍵:
</>復(fù)制代碼
> db.blog.find()
{
"_id" : ObjectId("5037ee4a1084eb3ffeef7228"),
"title" : "My Blog Post",
"content" : "Here"s my blog post.",
"date" : ISODate("2012-08-24T21:12:09.982Z"),
"comments" : [ ]
}
4. 刪除
使用remove方法可將文檔從數(shù)據(jù)庫中永久刪除。如果沒有使用任何參數(shù),它會將集合內(nèi)的所有文檔全部刪除。它可以接受一個作為限定條件的文檔作為參數(shù)。例如,下面的命令會刪除剛剛創(chuàng)建的文章:
</>復(fù)制代碼
> db.blog.remove({title : "My Blog Post"})
現(xiàn)在,集合又是空的了。
</>復(fù)制代碼
上一篇文章:MongoDB指南---1、MongoDB簡介
下一篇文章:MongoDB指南---3、MongoDB基礎(chǔ)知識-數(shù)據(jù)類型
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/43992.html
摘要:上一篇文章指南簡介下一篇文章指南基礎(chǔ)知識數(shù)據(jù)類型非常強(qiáng)大但很容易上手。把同種類型的文檔放在一個集合里,數(shù)據(jù)會更加集中。命名集合使用名稱進(jìn)行標(biāo)識。集合名不能是空字符串。簡單起見,數(shù)據(jù)庫名應(yīng)全部小寫。 上一篇文章:MongoDB指南---1、MongoDB簡介下一篇文章:MongoDB指南---3、MongoDB基礎(chǔ)知識-數(shù)據(jù)類型 MongoDB非常強(qiáng)大但很容易上手。本章會介紹一些Mon...
摘要:如將構(gòu)造函數(shù)作為函數(shù)進(jìn)行調(diào)用即不包括的方式,返回的是日期的字符串表示,而非日期對象。如果不注意這一點,沒有始終使用日期構(gòu)造函數(shù),將得到一堆混亂的日期對象和日期的字符串。關(guān)于日期類的完整解釋,以及構(gòu)造函數(shù)的參數(shù)格式,參見規(guī)范節(jié)。 上一篇文章:MongoDB指南---2、MongoDB基礎(chǔ)知識-文檔、集合、數(shù)據(jù)庫、客戶端下一篇文章:MongoDB指南---4、MongoDB基礎(chǔ)知識-使用M...
摘要:如將構(gòu)造函數(shù)作為函數(shù)進(jìn)行調(diào)用即不包括的方式,返回的是日期的字符串表示,而非日期對象。如果不注意這一點,沒有始終使用日期構(gòu)造函數(shù),將得到一堆混亂的日期對象和日期的字符串。關(guān)于日期類的完整解釋,以及構(gòu)造函數(shù)的參數(shù)格式,參見規(guī)范節(jié)。 上一篇文章:MongoDB指南---2、MongoDB基礎(chǔ)知識-文檔、集合、數(shù)據(jù)庫、客戶端下一篇文章:MongoDB指南---4、MongoDB基礎(chǔ)知識-使用M...
摘要:不采用關(guān)系模型主要是為了獲得更好的擴(kuò)展性。易于擴(kuò)展應(yīng)用程序數(shù)據(jù)集的大小正在以不可思議的速度增長。過去非常罕見的級別數(shù)據(jù),現(xiàn)在已是司空見慣了。這種精簡方式的設(shè)計是能夠?qū)崿F(xiàn)如此高性能的原因之一。下一篇文章指南基礎(chǔ)知識文檔集合數(shù)據(jù)庫客戶端 下一篇文章:MongoDB指南---2、MongoDB基礎(chǔ)知識-文檔、集合、數(shù)據(jù)庫、客戶端 MongoDB是一款強(qiáng)大、靈活,且易于擴(kuò)展的通用型數(shù)據(jù)庫。它...
摘要:不采用關(guān)系模型主要是為了獲得更好的擴(kuò)展性。易于擴(kuò)展應(yīng)用程序數(shù)據(jù)集的大小正在以不可思議的速度增長。過去非常罕見的級別數(shù)據(jù),現(xiàn)在已是司空見慣了。這種精簡方式的設(shè)計是能夠?qū)崿F(xiàn)如此高性能的原因之一。下一篇文章指南基礎(chǔ)知識文檔集合數(shù)據(jù)庫客戶端 下一篇文章:MongoDB指南---2、MongoDB基礎(chǔ)知識-文檔、集合、數(shù)據(jù)庫、客戶端 MongoDB是一款強(qiáng)大、靈活,且易于擴(kuò)展的通用型數(shù)據(jù)庫。它...
閱讀 3141·2021-11-11 16:54
閱讀 2313·2021-09-04 16:48
閱讀 3224·2019-08-29 16:08
閱讀 646·2019-08-29 15:13
閱讀 1349·2019-08-29 15:09
閱讀 2668·2019-08-29 12:45
閱讀 1931·2019-08-29 12:12
閱讀 453·2019-08-26 18:27