<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>我想网 &#187; Database</title>
	<atom:link href="http://www.iwanna.cn/tags/db/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.iwanna.cn</link>
	<description></description>
	<lastBuildDate>Mon, 26 Dec 2011 05:46:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>5款优秀免费在线数据备份/存储工具</title>
		<link>http://www.iwanna.cn/archives/2011/03/17/6368/</link>
		<comments>http://www.iwanna.cn/archives/2011/03/17/6368/#comments</comments>
		<pubDate>Thu, 17 Mar 2011 14:45:53 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Tool]]></category>
		<category><![CDATA[Free]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=6368</guid>
		<description><![CDATA[数据备份非常重要，无论是为了避免系统发生故障造成损失，还是平日对重要数据进行管理。当然你可以选择使用第二个硬盘对数据进行备份管理，问题是如 果可以不花钱就能做到这一点，何乐而不为？此外，你也很难保证你的第二块硬盘不不会发生故障吧。因此，选择一些有保证的在线存储备份服务是非常不错的主 意。 在线存储工具非常之多，在去年年底我为大家总结了“2010年最佳国外免费在线存储服务”。现在再为大家介绍5款优秀的免费在线数据备份存储工具： Windows Live SkyDrive Windows Live Skydrive是非常流行的基于云计算的服务，提供25GB的免费存储空间。SkyDrive的使用非常简单，首先使用你的Live ID登录为Windows Live Skydrive账户。然后就像简单的拖放文件那样就行了，你可以根据需要在不同文件夹间拖放文件。每一个文件夹都有一个固定链接，这样你就可以轻易地与 你的朋友、家人或者网友进行分享。此外，你可以对个人私密文件夹进行加密保护。 Binfire Binfire是另一家在线备份服务商，提供10GB的免费存储空间。它类似于Skydrive可创建私密文件夹或者共享文件夹。此 外，Binfire还是一个项目管理工具。它支持它支持项目仪表盘，任务计划和里程碑功能，项目群聊和使用tweets进行情况报告。 即使你对项目管理功能不感兴趣，你也可以使用它提供的免费在线存储空间对一些文件进行备份管理。 Idrive Idrive是另一款在线备份工具，提供5GB的免费存储空间。如果你需要更大的Idrive存储空间，你得付出一定的价钱。例如，Idrive提 供150GB的付费存储存储空间，每个月需要支付4.95美金（用户群明显不是针对中国大陆的网名）。还有一个家庭套餐，提供500GB的存储空间，运行 5个家庭成员共同使用，每个月则高达14.95美金。为了保证您的数据安全，iDrive提供了128 位SSL加密传输，256位AES加密存储。 GMail Drive Gmail Drive又是一款不错的免费在线备份存储空间。你只需要一个Gmail账户即可建立一个虚拟文件系统，并运行你使用Gmail作为存储介质，因此 Gmail用户使用起来非常方便。 什么是Gmail驱动器，使用Gmail帐户在本地创建一个虚拟文件系统，你可以像Windows资源管理那样直接存储和检索数据。你可以在这个驱 动器上创建文件夹和复制内容，所使用的存储空间是Gmail的存储空间（超过6GB）。 当然，还有许许多多在线备份存储空间，这里只列举期中比较常见和出名的免费在线备份存储空间。此前介绍的12个在线存储空间也是不错的选择，你可以有多个选择，毕竟备份重要数据，最好能够做到多管齐下，有备无患。﻿ © 我想网 Akon 所有 , 2011. &#124; 永久链接 &#124; 1条评论 &#124; 提交到 Google Reader 鲜果 抓虾 Feed enhanced by Better Feed from Ozh]]></description>
			<content:encoded><![CDATA[<p>数据备份非常重要，无论是为了避免系统发生故障造成损失，还是平日对重要数据进行管理。当然你可以选择使用第二个硬盘对数据进行备份管理，问题是如 果可以不花钱就能做到这一点，何乐而不为？此外，你也很难保证你的第二块硬盘不不会发生故障吧。因此，选择一些有保证的在线存储备份服务是非常不错的主 意。</p>
<p><a href="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233220948875328.jpg"><img title="online-storage" src="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233220948875328.jpg" alt="online storage " width="480" height="196" /></a></p>
<p>在线存储工具非常之多，在去年年底我为大家总结了“<a title="2010年最佳国外免费在线存储服务" href="http://www.iwanna.cn/archives/2011/03/17/6367/" target="_blank">2010年最佳国外免费在线存储服务</a>”。现在再为大家介绍5款优秀的免费在线数据备份存储工具：</p>
<h3><a title="Windows Live SkyDrive - Free Microsoft Online Data  Storage" href="http://explore.live.com/windows-live-skydrive" target="_blank">Windows Live SkyDrive</a></h3>
<p><a href="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/12332311012217036.jpg"><img title="Windows-Live-Sky-Drive" src="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/12332311012217036.jpg" alt="Windows Live Sky Drive " width="480" height="194" /></a><br />
Windows Live  Skydrive是非常流行的基于云计算的服务，提供25GB的免费存储空间。SkyDrive的使用非常简单，首先使用你的Live  ID登录为Windows Live  Skydrive账户。然后就像简单的拖放文件那样就行了，你可以根据需要在不同文件夹间拖放文件。每一个文件夹都有一个固定链接，这样你就可以轻易地与 你的朋友、家人或者网友进行分享。此外，你可以对个人私密文件夹进行加密保护。<br />
<span id="more-6368"></span></p>
<h3><a title="Binfire - Free Online Storage and data backup tool" href="http://www.techmixer.com/free-online-storage-backup-tools/www.binfire.com" target="_blank">Binfire</a></h3>
<p><a href="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/12332321948249658.jpg"><img title="Binfire" src="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/12332321948249658.jpg" alt="Binfire " width="480" height="247" /></a></p>
<p>Binfire是另一家在线备份服务商，提供10GB的免费存储空间。它类似于Skydrive可创建私密文件夹或者共享文件夹。此 外，Binfire还是一个项目管理工具。它支持它支持项目仪表盘，任务计划和里程碑功能，项目群聊和使用tweets进行情况报告。</p>
<p>即使你对项目管理功能不感兴趣，你也可以使用它提供的免费在线存储空间对一些文件进行备份管理。</p>
<h3><a title="Idrive - Free Online Backup Storage" href="http://www.idrive.com/" target="_blank">Idrive</a></h3>
<p><a href="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233233249609215.jpg"><img title="IDrive" src="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233233249609215.jpg" alt="IDrive " width="480" height="389" /></a></p>
<p>Idrive是另一款在线备份工具，提供5GB的免费存储空间。如果你需要更大的Idrive存储空间，你得付出一定的价钱。例如，Idrive提 供150GB的付费存储存储空间，每个月需要支付4.95美金（用户群明显不是针对中国大陆的网名）。还有一个家庭套餐，提供500GB的存储空间，运行 5个家庭成员共同使用，每个月则高达14.95美金。为了保证您的数据安全，iDrive提供了128 位SSL加密传输，256位AES加密存储。</p>
<h3><a title="Gmail Drive - Store data on Gmail" href="http://www.viksoe.dk/code/gmail.htm" target="_blank">GMail Drive</a></h3>
<p><a href="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233234493518936.jpg"><img title="GmailDrive" src="http://images.uheed.com/iwanna/2011/03/17/five-database-tools/1233234493518936.jpg" alt="GmailDrive " width="480" height="291" /></a></p>
<p>Gmail  Drive又是一款不错的免费在线备份存储空间。你只需要一个Gmail账户即可建立一个虚拟文件系统，并运行你使用Gmail作为存储介质，因此 Gmail用户使用起来非常方便。</p>
<p>什么是Gmail驱动器，使用Gmail帐户在本地创建一个虚拟文件系统，你可以像Windows资源管理那样直接存储和检索数据。你可以在这个驱 动器上创建文件夹和复制内容，所使用的存储空间是Gmail的存储空间（超过6GB）。</p>
<p>当然，还有许许多多在线备份存储空间，这里只列举期中比较常见和出名的免费在线备份存储空间。此前介绍的<a href="http://www.x-berry.com/best-free-sharing-services-of-2010" target="_blank">12个在线存储空间</a>也是不错的选择，你可以有多个选择，毕竟备份重要数据，最好能够做到多管齐下，有备无患。﻿</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2011. |
<a href="http://www.iwanna.cn/archives/2011/03/17/6368/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2011/03/17/6368/#comments">1条评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2011/03/17/6368/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2011/03/17/6368/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2011/03/17/6368/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2011/03/17/6368/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>五个免费开源的数据挖掘软件</title>
		<link>http://www.iwanna.cn/archives/2010/12/25/6158/</link>
		<comments>http://www.iwanna.cn/archives/2010/12/25/6158/#comments</comments>
		<pubDate>Sat, 25 Dec 2010 15:14:42 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[我想想想]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Free]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=6158</guid>
		<description><![CDATA[最近一段时间，我们网站升级。很多数据结构和URL结构变化很多，让很多数据都失去了监控。很幸运的是看到了这篇文章，提供了5个免费开源的数据挖掘软件，分享给大家。另外Google analytics 也是非常棒的数据挖掘和分析工具，建议大家好好研究这些工具。 Orange Orange 是一个基于组件的数据挖掘和机器学习软件套装，它的功能即友好，又很强大，快速而又多功能的可视化编程前端，以便浏览数据分析和可视化，基绑定了Python以进行脚本开发。它包含了完整的一系列的组件以进行数据预处理，并提供了数据帐目，过渡，建模，模式评估和勘探的功能。其由C++ 和 Python开发，它的图形库是由跨平台的Qt框架开发。 RapidMiner RapidMiner, 以前叫 YALE (Yet Another Learning Environment), 其是一个给机器学习和数据挖掘和分析的试验环境，同时用于研究了真实世界数据挖掘。它提供的实验由大量的算子组成，而这些算子由详细的XML文件记录，并被RapidMiner图形化的用户接口表现出来。RapidMiner为主要的机器学习过程提供了超过500算子，并且，其结合了学习方案 和Weka学习环境的属性评估器。它是一个独立的工具可以用来做数据分析，同样也是一个数据挖掘引擎可以用来集成到你的产品中。 Weka 由Java开发的 Weka (Waikato Environment for Knowledge Analysis) 是一个知名机器学机软件，其支持几种经典的数据挖掘任务，显著的数据预处理，集群，分类，回归，虚拟化，以及功能选择。其技术基于假设数据是以一种单个文件或关联的，在那里，每个数据点都被许多属性标注。 Weka 使用Java的数据库链接能力可以访问SQL数据库，并可以处理一个数据库的查询结果。它主要的用户接品是Explorer，也同样支持相同功能的命令 行，或是一种基于组件的知识流接口。 JHepWork 为科学家，工程师和学生所设计的 jHepWork 是一个免费的开源数据分析框架，其主要是用开源库来创建一个数据分析环境，并提供了丰富的用户接口，以此来和那些收费的的软件竞争。它主要是为了科学计算用的二维和三维的制图，并包含了用Java实现的数学科学库，随机数，和其它的数据挖掘算法。jHepWork 是基于一个高级的编程语言 Jython，当然，Java代码同样可以用来调用 jHepWork 的数学和图形库。 KNIME KNIME (Konstanz Information Miner) 是一个用户友好，智能的，并有丰演的开源的数以及可交互的视图。KNIME 由Java写成，其基于 Eclipse 并通过插件的方式来提供更多的功能。通过以插件的文件，用户可以为文件，图片，和时间序列加入处理模块，并可以集成到其它各种各样的开源项目中，比如：R 语言，Weka， Chemistry Development Kit, 和 LibSVM. © 我想网 [...]]]></description>
			<content:encoded><![CDATA[<p>最近一段时间，我们网站升级。很多数据结构和URL结构变化很多，让很多数据都失去了监控。很幸运的是看到了这篇文章，提供了5个免费开源的数据挖掘软件，分享给大家。另外Google analytics 也是非常棒的数据挖掘和分析工具，建议大家好好研究这些工具。</p>
<p><strong>Orange</strong></p>
<p><a href="http://www.ailab.si/orange"><img src="http://images.uheed.com/iwanna/2010/12/25/free-data-mining-software/orange-data-mining-software.jpg" border="0" alt="五个免费开源的数据挖掘软件 | iwanna.cn 我想网" /></a><a href="http://www.ailab.si/orange">Orange</a> 是一个基于组件的数据挖掘和机器学习软件套装，它的功能即友好，又很强大，快速而又多功能的可视化编程前端，以便浏览数据分析和可视化，基绑定了Python以进行脚本开发。它包含了完整的一系列的组件以进行数据预处理，并提供了数据帐目，过渡，建模，模式评估和勘探的功能。其由C++ 和 Python开发，它的图形库是由跨平台的Qt框架开发。<br />
<span id="more-6158"></span></p>
<h4>RapidMiner</h4>
<p><a href="http://rapidminer.com/" target="_blank"><img src="http://images.uheed.com/iwanna/2010/12/25/free-data-mining-software/data-mining-software-rapidminer.jpg" border="0" alt="五个免费开源的数据挖掘软件 | iwanna.cn 我想网" /></a><a href="http://rapidminer.com/" target="_blank">RapidMiner</a>,  以前叫 YALE (Yet Another Learning Environment),  其是一个给机器学习和数据挖掘和分析的试验环境，同时用于研究了真实世界数据挖掘。它提供的实验由大量的算子组成，而这些算子由详细的XML文件记录，并被RapidMiner图形化的用户接口表现出来。RapidMiner为主要的机器学习过程提供了超过500算子，并且，其结合了学习方案 和Weka学习环境的属性评估器。它是一个独立的工具可以用来做数据分析，同样也是一个数据挖掘引擎可以用来集成到你的产品中。</p>
<h4>Weka</h4>
<p><a href="http://www.cs.waikato.ac.nz/%7Eml/weka/" target="_blank"><img src="http://images.uheed.com/iwanna/2010/12/25/free-data-mining-software/data-mining-software-weka.jpg" border="0" alt="五个免费开源的数据挖掘软件 | iwanna.cn 我想网" /></a>由Java开发的 <a href="http://www.cs.waikato.ac.nz/%7Eml/weka/" target="_blank">Weka</a> (Waikato Environment for Knowledge Analysis)  是一个知名机器学机软件，其支持几种经典的数据挖掘任务，显著的数据预处理，集群，分类，回归，虚拟化，以及功能选择。其技术基于假设数据是以一种单个文件或关联的，在那里，每个数据点都被许多属性标注。 Weka  使用Java的数据库链接能力可以访问SQL数据库，并可以处理一个数据库的查询结果。它主要的用户接品是Explorer，也同样支持相同功能的命令 行，或是一种基于组件的知识流接口。</p>
<h4>JHepWork</h4>
<p><a href="http://jwork.org/jhepwork/" target="_blank"><img src="http://images.uheed.com/iwanna/2010/12/25/free-data-mining-software/data_mining_software_jhepwork.jpg" border="0" alt="五个免费开源的数据挖掘软件 | iwanna.cn 我想网" width="98" height="88" /></a>为科学家，工程师和学生所设计的 <a href="http://jwork.org/jhepwork/" target="_blank">jHepWork</a> 是一个免费的开源数据分析框架，其主要是用开源库来创建一个数据分析环境，并提供了丰富的用户接口，以此来和那些收费的的软件竞争。它主要是为了科学计算用的二维和三维的制图，并包含了用Java实现的数学科学库，随机数，和其它的数据挖掘算法。jHepWork 是基于一个高级的编程语言 Jython，当然，Java代码同样可以用来调用  jHepWork 的数学和图形库。</p>
<h4>KNIME</h4>
<p><a href="http://www.knime.org/" target="_blank"><img src="http://images.uheed.com/iwanna/2010/12/25/free-data-mining-software/data-mining-software-KNIME.jpg" border="0" alt="五个免费开源的数据挖掘软件 | iwanna.cn 我想网" /></a><a href="http://www.knime.org/" target="_blank">KNIME</a> (Konstanz Information Miner)  是一个用户友好，智能的，并有丰演的开源的数以及可交互的视图。KNIME 由Java写成，其基于 Eclipse 并通过插件的方式来提供更多的功能。通过以插件的文件，用户可以为文件，图片，和时间序列加入处理模块，并可以集成到其它各种各样的开源项目中，比如：R 语言，Weka， Chemistry Development Kit, 和 LibSVM.</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/12/25/6158/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/12/25/6158/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/12/25/6158/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/12/25/6158/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/12/25/6158/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/12/25/6158/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB系列文章推荐</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5294/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5294/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:16:34 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5294</guid>
		<description><![CDATA[今天才发现这么一系列的学习笔记，绝对算是一个失误。下面是一个长达十节的MongoDB系列文章，几乎可以称作简单的中文文档。非常实用而系统。 MongoDB: 1. Database MongoDB: 2. Basic Usage MongoDB: 3. Schema Design MongoDB: 4. Index MongoDB: 5. Admin MongoDB: 6. Optimization MongoDB: 7. Replication (1) MongoDB: 7. Replication (2) MongoDB: 8. Sharding (1) MongoDB: 8. Sharding (2) MongoDB: 9. Grid FS MongoDB: 10. MapReduce © 我想网 Akon 所有 , 2010. &#124; 永久链接 &#124; 没有评论 &#124; [...]]]></description>
			<content:encoded><![CDATA[<p>今天才发现这么一系列的学习笔记，绝对算是一个失误。下面是一个长达十节的MongoDB系列文章，几乎可以称作简单的中文文档。非常实用而系统。</p>
<ul>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5291/">MongoDB: 1.  Database</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5296/">MongoDB: 2.  Basic Usage</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5297/">MongoDB: 3.  Schema Design</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5300/">MongoDB: 4.  Index</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5301/">MongoDB: 5.  Admin</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5302/">MongoDB: 6.  Optimization</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5307/">MongoDB: 7.  Replication (1)</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5308/">MongoDB: 7.  Replication (2)</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5313/">MongoDB: 8.  Sharding (1)</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5310/">MongoDB: 8.  Sharding (2)</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5316/">MongoDB: 9.  Grid FS</a></li>
<li><a href="http://www.iwanna.cn/archives/2010/09/17/5319/">MongoDB: 10.  MapReduce</a></li>
</ul>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5294/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5294/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5294/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5294/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5294/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5294/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 10. MapReduce</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5319/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5319/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:15:52 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5319</guid>
		<description><![CDATA[在 MongoDB 上使用 Map/Reduce 进行并行 &#8220;统计&#8221; 很容易。 db.runCommand( { mapreduce : &#60;collection&#62;, map : &#60;mapfunction&#62;, reduce : &#60;reducefunction&#62; [, query : &#60;query filter object&#62;] [, sort : &#60;sort the query. useful optimization&#62;] for [, limit : &#60;number of objects to from collection&#62;] return [, out : &#60;output-collection name&#62;] [, keeptemp: &#60; &#124; &#62;] true false [...]]]></description>
			<content:encoded><![CDATA[<p>在 <a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 上使用 Map/Reduce 进行并行 &#8220;统计&#8221; 很容易。</p>
<pre>db.runCommand(
{
    mapreduce : &lt;collection&gt;,
    map : &lt;mapfunction&gt;,
    reduce : &lt;reducefunction&gt;
    [, query : &lt;query filter object&gt;]
    [, sort : &lt;sort the query.  useful   optimization&gt;] for
    [, limit : &lt;number of objects to   from collection&gt;] return
    [, out : &lt;output-collection name&gt;]
    [, keeptemp: &lt; | &gt;] true false
    [, finalize : &lt;finalizefunction&gt;]
    [, scope : &lt;object where fields go into javascript global scope &gt;]
    [, verbose :  ] true
});</pre>
<p><span id="more-5319"></span><br />
参数说明:</p>
<ul>
<li> mapreduce: 要操作的目标集合。</li>
<li> map: 映射函数 (生成键值对序列，作为 reduce 函数参数)。</li>
<li> reduce: 统计函数。</li>
<li> query: 目标记录过滤。</li>
<li> sort: 目标记录排序。</li>
<li> limit: 限制目标记录数量。</li>
<li> out: 统计结果存放集合 (不指定则使用临时集合，在客户端断开后自动删除)。</li>
<li> keeptemp: 是否保留临时集合。</li>
<li> finalize: 最终处理函数 (对 reduce 返回结果进行最终整理后存入结果集合)。</li>
<li> scope: 向  map、reduce、finalize 导入外部变量。</li>
<li> verbose: 显示详细的时间统计信息。</li>
</ul>
<p>官方文档 有几句话很重要：</p>
<pre>map/reduce is invoked via a <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">database</a>.  The <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">database</a> creates a temporary collection to hold output of the operation. The collection is command cleaned up when the client connection closes, or when explicitly dropped. Alternatively, one can specify a permanent output collection name. map and reduce functions are written in JavaScript and execute on the server. 

In sharded environments, data processing of map/reduce operations runs in parallel on all shards.

MapReduce jobs on a single mongod process are single threaded. This is due to a design limitation in current JavaScript engines. We are looking into alternatives to solve this issue, but for now if you want to parallelize your MapReduce jobs, you will need to either use sharding or do the aggregation client-side in your code.</pre>
<p>先 准备点简单的数据练练手。</p>
<pre>&gt; for (var i = 0; i &lt; 1000; i++) {
... var u = { name : "user" + i, age : i % 40 + 1, sex : i % 2 };
... db.users.insert(u);
... }

&gt; db.users.ensureIndex({name:1})
&gt; db.users.ensureIndex({age:1})

&gt; db.users.count()
1000

&gt; db.users.find().limit(10)
{ "_id" : ObjectId("4c89bf5b24280691541787b8"), "name" : "user0", "age" : 1, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787b9"), "name" : "user1", "age" : 2, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787ba"), "name" : "user2", "age" : 3, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bb"), "name" : "user3", "age" : 4, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787bc"), "name" : "user4", "age" : 5, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bd"), "name" : "user5", "age" : 6, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787be"), "name" : "user6", "age" : 7, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bf"), "name" : "user7", "age" : 8, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787c0"), "name" : "user8", "age" : 9, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787c1"), "name" : "user9", "age" : 10, "sex" : 1 }</pre>
<p><strong>1.  Map</strong></p>
<p>Map 函数必须调用 emit(key, value) 返回键值对，使用 this 访问当前待处理的  Document。</p>
<pre>&gt; m = function() { emit(this.age, 1) }

function () {
    emit(this.age, 1);
}</pre>
<p>value 可以使用 JSON Object 传递 (支持多个属性值)。</p>
<p>例如:</p>
<pre>emit(this.age, {count:1})</pre>
<p><strong>2.  Reduce</strong></p>
<p>Reduce 函数接收的参数类似 Group 效果，将 Map 返回的键值序列组合成 { key,  [value1, value2, value3, value...] } 传递给 reduce。</p>
<pre>&gt; r = function(key, values) {
... var x = 0;
... values.forEach(function(v) { x += v });
... return x;
... }

function (key, values) {
    var x = 0;
    values.forEach(function (v) {x += v;});
    return x;
}</pre>
<p>Reduce 函数对这些 values 进行 &#8220;统计&#8221; 操作，返回结果可以使用 JSON Object。</p>
<p><strong>3.  Result</strong></p>
<p>我们不必使用 runCommand，改用  db.&lt;collection&gt;.mapReduce() 更方便一些。</p>
<pre>&gt; res = db.users.mapReduce(m, r)
{
        "result" : "tmp.mr.mapreduce_1284097299_10",
        "timeMillis" : 156,
        "counts" : {
                "input" : 1000,
                "emit" : 1000,
                "output" : 40
        },
        "ok" : 1,
}

&gt; db[res.result].find()
{ "_id" : 1, "value" : 25 }
{ "_id" : 2, "value" : 25 }
{ "_id" : 3, "value" : 25 }
{ "_id" : 4, "value" : 25 }
{ "_id" : 5, "value" : 25 }
{ "_id" : 6, "value" : 25 }
{ "_id" : 7, "value" : 25 }
{ "_id" : 8, "value" : 25 }
{ "_id" : 9, "value" : 25 }
{ "_id" : 10, "value" : 25 }
{ "_id" : 11, "value" : 25 }
{ "_id" : 12, "value" : 25 }
{ "_id" : 13, "value" : 25 }
{ "_id" : 14, "value" : 25 }
{ "_id" : 15, "value" : 25 }
{ "_id" : 16, "value" : 25 }
{ "_id" : 17, "value" : 25 }
{ "_id" : 18, "value" : 25 }
{ "_id" : 19, "value" : 25 }
{ "_id" : 20, "value" : 25 }
has more</pre>
<p>mapReduce() 将结果存储在 &#8220;tmp.mr.mapreduce_1284097299_10&#8243;  临时集合中。</p>
<p><strong>4. Finalize</strong></p>
<p>利用 finalize() 我们可以对 reduce()  的结果做进一步处理。</p>
<pre>&gt; f = function(key, value) { return {age:key, count:value}; }

function (key, value) {
    return {age:key, count:value};
}

&gt; res = db.users.mapReduce(m, r, {finalize:f})
{
        "result" : "tmp.mr.mapreduce_1284098036_26",
        "timeMillis" : 158,
        "counts" : {
                "input" : 1000,
                "emit" : 1000,
                "output" : 40
        },
        "ok" : 1,
}

&gt; db[res.result].find()
{ "_id" : 1, "value" : { "age" : 1, "count" : 25 } }
{ "_id" : 2, "value" : { "age" : 2, "count" : 25 } }
{ "_id" : 3, "value" : { "age" : 3, "count" : 25 } }
{ "_id" : 4, "value" : { "age" : 4, "count" : 25 } }
{ "_id" : 5, "value" : { "age" : 5, "count" : 25 } }
{ "_id" : 6, "value" : { "age" : 6, "count" : 25 } }
{ "_id" : 7, "value" : { "age" : 7, "count" : 25 } }
{ "_id" : 8, "value" : { "age" : 8, "count" : 25 } }
{ "_id" : 9, "value" : { "age" : 9, "count" : 25 } }
{ "_id" : 10, "value" : { "age" : 10, "count" : 25 } }
{ "_id" : 11, "value" : { "age" : 11, "count" : 25 } }
{ "_id" : 12, "value" : { "age" : 12, "count" : 25 } }
{ "_id" : 13, "value" : { "age" : 13, "count" : 25 } }
{ "_id" : 14, "value" : { "age" : 14, "count" : 25 } }
{ "_id" : 15, "value" : { "age" : 15, "count" : 25 } }
{ "_id" : 16, "value" : { "age" : 16, "count" : 25 } }
{ "_id" : 17, "value" : { "age" : 17, "count" : 25 } }
{ "_id" : 18, "value" : { "age" : 18, "count" : 25 } }
{ "_id" : 19, "value" : { "age" : 19, "count" : 25 } }
{ "_id" : 20, "value" : { "age" : 20, "count" : 25 } }
has more</pre>
<p><strong>5. Options</strong></p>
<p>我们还可以添加更多的控制细节。</p>
<pre>&gt; res = db.users.mapReduce(m, r, {query:{age:{$lt:10}}, sort:{name:1}, limit:5})
{
        "result" : "tmp.mr.mapreduce_1284097888_25",
        "timeMillis" : 20,
        "counts" : {
                "input" : 5,
                "emit" : 5,
                "output" : 3
        },
        "ok" : 1,
}

&gt; db[res.result].find()
{ "_id" : 1, "value" : 2 }
{ "_id" : 2, "value" : 2 }
{ "_id" : 3, "value" : 1 }</pre>
<p><strong>6. Example</strong></p>
<p>MapReduce  的作用不仅仅是 &#8220;统计&#8221;，我们可以直接用这种在服务器端高速并发执行机制批量修改数据。</p>
<pre>&gt; m = function() { emit(this._id, this) }

function () {
    emit(this._id, this);
}

&gt; r = function(key, values) {
... update = function(v) {
...     db.users.update({_id:key}, {$inc:{age:1}}, false, false);
... }
... values.forEach(update);
... return key;
... }

function (key, values) {
    update = function (v) {db.users.update({_id:key}, {$inc:{age:1}}, false, false);};
    values.forEach(update);
    return key;
}

&gt; db.users.find().limit(10)
{ "_id" : ObjectId("4c89bf5b24280691541787b8"), "name" : "user0", "age" : 1, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787b9"), "name" : "user1", "age" : 2, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787ba"), "name" : "user2", "age" : 3, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bb"), "name" : "user3", "age" : 4, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787bc"), "name" : "user4", "age" : 5, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bd"), "name" : "user5", "age" : 6, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787be"), "name" : "user6", "age" : 7, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bf"), "name" : "user7", "age" : 8, "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787c0"), "name" : "user8", "age" : 9, "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787c1"), "name" : "user9", "age" : 10, "sex" : 1 }

&gt; res = db.users.mapReduce(m, r, {limit:10})
{
        "result" : "tmp.mr.mapreduce_1284098486_27",
        "timeMillis" : 28,
        "counts" : {
                "input" : 10,
                "emit" : 10,
                "output" : 10
        },
        "ok" : 1,
}

&gt; db.users.find().limit(10)
{ "_id" : ObjectId("4c89bf5b24280691541787b8"), "age" : 2, "name" : "user0", "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787b9"), "age" : 3, "name" : "user1", "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787ba"), "age" : 4, "name" : "user2", "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bb"), "age" : 5, "name" : "user3", "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787bc"), "age" : 6, "name" : "user4", "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bd"), "age" : 7, "name" : "user5", "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787be"), "age" : 8, "name" : "user6", "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787bf"), "age" : 9, "name" : "user7", "sex" : 1 }
{ "_id" : ObjectId("4c89bf5b24280691541787c0"), "age" : 10, "name" : "user8", "sex" : 0 }
{ "_id" : ObjectId("4c89bf5b24280691541787c1"), "age" : 11, "name" : "user9", "sex" : 1 }</pre>
<p><strong>7.  PyMongo</strong></p>
<p>最后当然得在 Python 调用一下。</p>
<pre>In [1]: from pymongo import *

In [2]: conn = Connection()

In [3]: db = conn.test

In [4]: m = "function() { emit(this.age, 1); }"

In [5]: r = "function(key, values) { var x = 0; values.forEach(function(v){ x += v }); return x; }"

In [6]: res = db.users.map_reduce(m, r, True)

In [7]: for k in db[res["result"]].find(): print k
   ....:
{u'_id': 1.0, u'value': 24.0}
{u'_id': 2.0, u'value': 25.0}
{u'_id': 3.0, u'value': 25.0}
{u'_id': 4.0, u'value': 25.0}
{u'_id': 5.0, u'value': 25.0}
{u'_id': 6.0, u'value': 25.0}
{u'_id': 7.0, u'value': 25.0}
{u'_id': 8.0, u'value': 25.0}
{u'_id': 9.0, u'value': 25.0}
{u'_id': 10.0, u'value': 25.0}
{u'_id': 11.0, u'value': 26.0}
{u'_id': 12.0, u'value': 25.0}
{u'_id': 13.0, u'value': 25.0}
{u'_id': 14.0, u'value': 25.0}
{u'_id': 15.0, u'value': 25.0}
{u'_id': 16.0, u'value': 25.0}
{u'_id': 17.0, u'value': 25.0}
{u'_id': 18.0, u'value': 25.0}
{u'_id': 19.0, u'value': 25.0}
{u'_id': 20.0, u'value': 25.0}
{u'_id': 21.0, u'value': 25.0}
{u'_id': 22.0, u'value': 25.0}
{u'_id': 23.0, u'value': 25.0}
{u'_id': 24.0, u'value': 25.0}
{u'_id': 25.0, u'value': 25.0}
{u'_id': 26.0, u'value': 25.0}
{u'_id': 27.0, u'value': 25.0}
{u'_id': 28.0, u'value': 25.0}
{u'_id': 29.0, u'value': 25.0}
{u'_id': 30.0, u'value': 25.0}
{u'_id': 31.0, u'value': 25.0}
{u'_id': 32.0, u'value': 25.0}
{u'_id': 33.0, u'value': 25.0}
{u'_id': 34.0, u'value': 25.0}
{u'_id': 35.0, u'value': 25.0}
{u'_id': 36.0, u'value': 25.0}
{u'_id': 37.0, u'value': 25.0}
{u'_id': 38.0, u'value': 25.0}
{u'_id': 39.0, u'value': 25.0}
{u'_id': 40.0, u'value': 25.0}</pre>
<p>附加参数也很容易。</p>
<pre>In [10]: res = db.users.map_reduce(m, r, True, limit=10)

In [11]: res
Out[11]:
{u'counts': {u'emit': 10, u'input': 10, u'output': 10},
 u'ok': 1.0,
 u'result': u'tmp.mr.mapreduce_1284099468_31',
 u'timeMillis': 20}

In [12]: for k in db[res["result"]].find(): print k
   ....:
{u'_id': 2.0, u'value': 1.0}
{u'_id': 3.0, u'value': 1.0}
{u'_id': 4.0, u'value': 1.0}
{u'_id': 5.0, u'value': 1.0}
{u'_id': 6.0, u'value': 1.0}
{u'_id': 7.0, u'value': 1.0}
{u'_id': 8.0, u'value': 1.0}
{u'_id': 9.0, u'value': 1.0}
{u'_id': 10.0, u'value': 1.0}
{u'_id': 11.0, u'value': 1.0}

In [13]: res = db.users.map_reduce(m, r, True, query={"age":{"$lt":20}})

In [14]: res
Out[14]:
{u'counts': {u'emit': 475, u'input': 475, u'output': 19},
 u'ok': 1.0,
 u'result': u'tmp.mr.mapreduce_1284099533_33',
 u'timeMillis': 77}

In [15]: for k in db[res["result"]].find(): print k
   ....:
{u'_id': 1.0, u'value': 24.0}
{u'_id': 2.0, u'value': 25.0}
{u'_id': 3.0, u'value': 25.0}
{u'_id': 4.0, u'value': 25.0}
{u'_id': 5.0, u'value': 25.0}
{u'_id': 6.0, u'value': 25.0}
{u'_id': 7.0, u'value': 25.0}
{u'_id': 8.0, u'value': 25.0}
{u'_id': 9.0, u'value': 25.0}
{u'_id': 10.0, u'value': 25.0}
{u'_id': 11.0, u'value': 26.0}
{u'_id': 12.0, u'value': 25.0}
{u'_id': 13.0, u'value': 25.0}
{u'_id': 14.0, u'value': 25.0}
{u'_id': 15.0, u'value': 25.0}
{u'_id': 16.0, u'value': 25.0}
{u'_id': 17.0, u'value': 25.0}
{u'_id': 18.0, u'value': 25.0}
{u'_id': 19.0, u'value': 25.0}</pre>
<p>更多细节参考官方文档。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5319/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5319/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5319/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5319/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5319/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5319/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 9. Grid FS</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5316/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5316/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:14:45 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5316</guid>
		<description><![CDATA[GridFS 的文件同样是保存在 db.collection 中，通常使用 fs.files 存储文件元数据信息，fs.chunks 存储文件内容。 存储海量文件，得启用 Auto-Sharding。 &#62; admin.runCommand({ enablesharding: test }) &#62; admin.runCommand({ shardcollection: test.fs.chunks, key:{files_id:1} }) PyMongo API 中有个 GridFS 对象，使用方法很简单。 &#62;&#62;&#62; from pymongo import * &#62;&#62;&#62; from pymongo.objectid import ObjectId &#62;&#62;&#62; from gridfs import * &#62;&#62;&#62; from pprint import pprint &#62;&#62;&#62; conn = Connection() &#62;&#62;&#62; db = conn.test &#62;&#62;&#62; gfs [...]]]></description>
			<content:encoded><![CDATA[<p>GridFS 的文件同样是保存在 db.collection 中，通常使用 fs.files 存储文件元数据信息，fs.chunks  存储文件内容。</p>
<p>存储海量文件，得启用 Auto-Sharding。</p>
<pre>&gt; admin.runCommand({ enablesharding: test })
&gt; admin.runCommand({ shardcollection: test.fs.chunks, key:{files_id:1} })</pre>
<p><a title="http://api.mongodb.org/python/current/index.html" href="http://api.mongodb.org/python/current/index.html" target="_blank">PyMongo</a> API 中有个 <a title="http://api.mongodb.org/python/current/api/gridfs/index.html" href="http://api.mongodb.org/python/current/api/gridfs/index.html" target="_blank">GridFS</a> 对象，使用方法很简单。</p>
<pre>&gt;&gt;&gt; from pymongo import *
&gt;&gt;&gt; from pymongo.objectid import ObjectId
&gt;&gt;&gt; from gridfs import *
&gt;&gt;&gt; from pprint import pprint

&gt;&gt;&gt; conn = Connection()
&gt;&gt;&gt; db = conn.test
&gt;&gt;&gt; gfs = GridFS(db)</pre>
<p>随便找个文件存到 GridFS 中，除了必须的 filename  外，还可以附加任意属性。<br />
<span id="more-5316"></span></p>
<pre>&gt;&gt;&gt; with open("/home/yuhen/a.txt", "r") as file:
...     id = gfs.put(file.read(), filename = "/xxx/xxx/a.txt", upload = "q.yuhen", abc = 123)
...     print id
...
4c85e1f8499b144773000000

&gt;&gt;&gt; gfs.list()
[u'/xxx/xxx/a.txt']</pre>
<p>用 mongo 看看数据库中存储的具体信息。</p>
<pre>$ ./mongo

<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> shell version: 1.6.2
connecting to: test

&gt; show collections
fs.chunks
fs.files
system.indexes

&gt; db.fs.files.find()
{
    "_id" : ObjectId("4c85e1f8499b144773000000"),
    "abc" : 123,
    "chunkSize" : 262144,
    "upload" : "q.yuhen",
    "filename" : "/xxx/xxx/a.txt",
    "length" : 14,
    "uploadDate" : "Tue Sep 07 2010 14:55:52 GMT+0800 (CST)",
    "md5" : "284d1d15a9d681b288cb5915ada39f53"
}

&gt; db.fs.chunks.find()
{
    "_id" : ObjectId("4c85e1f8499b144773000001"),
    "n" : 0,
    "data" : BinData(2,"DgAAAGFiY2VmZywgaGVsbG8K"),
    "files_id" : ObjectId("4c85e1f8499b144773000000")
}</pre>
<p>我们可以用 file_id 读取文件数据(包括文件内容和附加属性)。</p>
<pre>&gt;&gt;&gt; with open("/home/yuhen/a2.txt", "w") as file:
...     out = gfs.get(ObjectId("4c85e1f8499b144773000000"))
...     file.write(out.read())
...     pprint(dir(out))
...     pprint(out._file.items())
...     print out.name
...     print out.upload
...     print out.abc
...

[
 ...,
 '_file',
 '_id',
 'aliases',
 'chunk_size',
 'content_type',
 'length',
 'md5',
 'metadata',
 'name',
 'read',
 'seek',
 'tell',
 'upload_date'
]

[
 (u'abc', 123),
 (u'chunkSize', 262144),
 (u'upload', u'q.yuhen'),
 (u'filename', u'/xxx/xxx/a.txt'),
 (u'length', 14),
 (u'uploadDate', datetime.datetime(2010, 9, 7, 6, 55, 52, 611000)),
 (u'_id', ObjectId('4c85e1f8499b144773000000')),
 (u'md5', u'284d1d15a9d681b288cb5915ada39f53')
]

/xxx/xxx/a.txt
q.yuhen
123</pre>
<p>还可以用 filename 读取文件。在应用中我们通常要确保 filename 唯一性。</p>
<pre>&gt;&gt;&gt; with open("/home/yuhen/a3.txt", "w") as file:
...     out = gfs.get_last_version("/xxx/xxx/a.txt")
...     file.write(out.read())
...     print out.name, out.length
...

/xxx/xxx/a.txt 14</pre>
<p>用相同的 filename  存储同一文件的不同版本是允许的，数据库中会保留所有历史数据。但用 get_last_version(filename)  只能取回最后一次的更新数据，可以直接从 db.fs.files 中查询 file_id 来获取不同版本内容。</p>
<pre>&gt;&gt;&gt; with open("/home/yuhen/a.txt", "r") as file:
...     id = gfs.put(file.read(), filename = "/xxx/xxx/a.txt", upload = "q.yuhen", abc = 456)
...     print id
...
4c85e70a499b144773000004

&gt;&gt;&gt; gfs.list()
[u'/xxx/xxx/a.txt']

&gt;&gt;&gt; with open("/home/yuhen/a3.txt", "w") as file:
...     out = gfs.get_last_version("/xxx/xxx/a.txt")
...     file.write(out.read())
...     print out.name, out.length, out.abc
...
/xxx/xxx/a.txt 22 456

&gt;&gt;&gt; for f in db.fs.files.find({ "filename":"/xxx/xxx/a.txt" }):
...     print f["_id"], f["length"], f["abc"]
...
4c85e70a499b144773000004 22 456
4c85e1f8499b144773000000 14 123</pre>
<p>GridFS 还提供了 exists、delete  等方法。delete 按 file_id 删除，也就是说是文件的最后一个版本。</p>
<pre>&gt;&gt;&gt; def clear():
...     for f in gfs.list():
...         id = gfs.get_last_version(f)._id
...         print id
...         if gfs.exists(id): gfs.delete(id)
...

&gt;&gt;&gt; clear()
4c85e70a499b144773000004

&gt;&gt;&gt; gfs.list()
[u'/xxx/xxx/a.txt']

&gt;&gt;&gt; clear()
4c85e1f8499b144773000000

&gt;&gt;&gt; gfs.list()
[]</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5316/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5316/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5316/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5316/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5316/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5316/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 8. Sharding (2)</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5310/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5310/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:13:23 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5310</guid>
		<description><![CDATA[MongoDB Auto-Sharding 解决了海量存储和动态扩容的问题，但离实际生产环境所需的高可靠(high reliability)、高可用(high availability)还有些距离。 解决方案: Shard: 使用 Replica Sets，确保每个数据节点都具有备份、自动容错转移、自动恢复能力。 Config: 使用 3 个配置服务器，确保元数据完整性(two-phase commit)。 Route: 配合 LVS，实现负载平衡，提高接入性能(high performance)。 以下我们配置一个 Replica Sets + Sharding 测试环境。 装个配置过程建议都用 IP 地址，以免出错。 (1) 首先建好所有的数据库目录。 $ sudo mkdir -p /var/mongodb/10001 $ sudo mkdir -p /var/mongodb/10002 $ sudo mkdir -p /var/mongodb/10003 $ sudo mkdir -p /var/mongodb/10011 $ sudo mkdir -p /var/mongodb/10012 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> Auto-Sharding 解决了海量存储和动态扩容的问题，但离实际生产环境所需的高可靠(high  reliability)、高可用(high availability)还有些距离。</p>
<p>解决方案:</p>
<ul>
<li> Shard: 使用 Replica  Sets，确保每个数据节点都具有备份、自动容错转移、自动恢复能力。</li>
<li> Config: 使用 3  个配置服务器，确保元数据完整性(two-phase commit)。</li>
<li> Route: 配合  LVS，实现负载平衡，提高接入性能(high performance)。</li>
</ul>
<p>以下我们配置一个 Replica Sets +  Sharding 测试环境。<br />
装个配置过程建议都用 IP 地址，以免出错。<br />
<span id="more-5310"></span><br />
(1) 首先建好所有的数据库目录。</p>
<pre>$ sudo mkdir -p /var/mongodb/10001
$ sudo mkdir -p /var/mongodb/10002
$ sudo mkdir -p /var/mongodb/10003

$ sudo mkdir -p /var/mongodb/10011
$ sudo mkdir -p /var/mongodb/10012
$ sudo mkdir -p /var/mongodb/10013

$ sudo mkdir -p /var/mongodb/config1
$ sudo mkdir -p /var/mongodb/config2
$ sudo mkdir -p /var/mongodb/config3</pre>
<p>(2) 配置 Shard Replica Sets。</p>
<pre>$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10001 --port 10001 --nohttpinterface --replSet set1
forked process: 4974
all output going to: /dev/null

$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10002 --port 10002 --nohttpinterface --replSet set1
forked process: 4988
all output going to: /dev/null

$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10003 --port 10003 --nohttpinterface --replSet set1
forked process: 5000
all output going to: /dev/null</pre>
<pre>$ ./mongo --port 10001

MongoDB shell version: 1.6.2
connecting to: 127.0.0.1:10001/test

&gt; cfg = { _id:'set1', members:[
... { _id:0, host:'192.168.1.202:10001' },
... { _id:1, host:'192.168.1.202:10002' },
... { _id:2, host:'192.168.1.202:10003' }
... ]};

&gt; rs.initiate(cfg)
{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}

&gt; rs.status()
{
        "set" : "set1",
        "date" : "Tue Sep 07 2010 10:25:28 GMT+0800 (CST)",
        "myState" : 5,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "yuhen-server64:10001",
                        "health" : 1,
                        "state" : 5,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "192.168.1.202:10002",
                        "health" : -1,
                        "state" : 6,
                        "uptime" : 0,
                        "lastHeartbeat" : "Thu Jan 01 1970 08:00:00 GMT+0800 (CST)"
                },
                {
                        "_id" : 2,
                        "name" : "192.168.1.202:10003",
                        "health" : -1,
                        "state" : 6,
                        "uptime" : 0,
                        "lastHeartbeat" : "Thu Jan 01 1970 08:00:00 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}</pre>
<p>配置第二组 Shard Replica Sets。</p>
<pre>$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10011 --port 10011 --nohttpinterface --replSet set2
forked process: 5086
all output going to: /dev/null

$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10012 --port 10012 --nohttpinterface --replSet set2
forked process: 5098
all output going to: /dev/null

$ sudo ./mongod --shardsvr --fork --logpath /dev/null --dbpath /var/mongodb/10013 --port 10013 --nohttpinterface --replSet set2
forked process: 5112
all output going to: /dev/null</pre>
<pre>$ ./mongo --port 10011

MongoDB shell version: 1.6.2
connecting to: 127.0.0.1:10011/test

&gt; cfg = { _id:'set2', members:[
... { _id:0, host:'192.168.1.202:10011' },
... { _id:1, host:'192.168.1.202:10012' },
... { _id:2, host:'192.168.1.202:10013' }
... ]}

&gt; rs.initiate(cfg)
{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}

&gt; rs.status()
{
        "set" : "set2",
        "date" : "Tue Sep 07 2010 10:28:37 GMT+0800 (CST)",
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "yuhen-server64:10011",
                        "health" : 1,
                        "state" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "192.168.1.202:10012",
                        "health" : 0,
                        "state" : 6,
                        "uptime" : 0,
                        "lastHeartbeat" : "Tue Sep 07 2010 10:28:36 GMT+0800 (CST)",
                        "errmsg" : "still initializing"
                },
                {
                        "_id" : 2,
                        "name" : "192.168.1.202:10013",
                        "health" : 1,
                        "state" : 5,
                        "uptime" : 1,
                        "lastHeartbeat" : "Tue Sep 07 2010 10:28:36 GMT+0800 (CST)",
                        "errmsg" : "."
                }
        ],
        "ok" : 1
}</pre>
<p>(3) 启动 Config Server。</p>
<p>我们可以只使用 1 个 Config Server，但 3  个理论上更有保障性。</p>
<pre>Chunk information is the main data stored by the config servers.  Each config server has a complete copy of all chunk information.  A two-phase
commit is used to ensure the consistency of the configuration data among the config servers.

If any of the config servers is down, the cluster's meta-data goes read only. However, even in such a failure state, the MongoDB cluster can still
be read from and written to.</pre>
<p>注意！这个不是 Replica Sets，不需要 &#8211;replSet  参数。</p>
<pre>$ sudo ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config1 --port 20000 --nohttpinterface
forked process: 5177
all output going to: /dev/null

$ sudo ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config2 --port 20001 --nohttpinterface
forked process: 5186
all output going to: /dev/null

$ sudo ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config3 --port 20002 --nohttpinterface
forked process: 5195
all output going to: /dev/null</pre>
<pre>$ ps aux | grep configsvr | grep -v grep
root  ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config1 --port 20000 --nohttpinterface
root  ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config2 --port 20001 --nohttpinterface
root  ./mongod --configsvr --fork --logpath /dev/null --dbpath /var/mongodb/config3 --port 20002 --nohttpinterface</pre>
<p>(4)  启动 Route Server。</p>
<p>注意 &#8211;configdb 参数。</p>
<pre>$ sudo ./mongos --fork --logpath /dev/null --configdb "192.168.1.202:20000,192.168.1.202:20001,192.168.1.202:20002"
forked process: 5209
all output going to: /dev/null</pre>
<pre>$ ps aux | grep mongos | grep -v grep
root ./mongos --fork --logpath /dev/null --configdb 192.168.1.202:20000,192.168.1.202:20001,192.168.1.202:20002</pre>
<p>(5)  开始配置 Sharding。</p>
<p>注意 addshard 添加 Replica Sets 的格式。</p>
<pre>$ ./mongo

MongoDB shell version: 1.6.2
connecting to: test

&gt; use admin
switched to db admin

&gt; db.runCommand({ addshard:'set1/192.168.1.202:10001,192.168.1.202:10002,192.168.1.202:10003' })
{ "shardAdded" : "set1", "ok" : 1 }

&gt; db.runCommand({ addshard:'set2/192.168.1.202:10011,192.168.1.202:10012,192.168.1.202:10013' })
{ "shardAdded" : "set2", "ok" : 1 }

&gt; db.runCommand({ enablesharding:'test' })
{ "ok" : 1 }

&gt; db.runCommand({ shardcollection:'test.data', key:{_id:1} })
{ "collectionsharded" : "test.data", "ok" : 1 }

&gt; db.runCommand({ listshards:1 })
{
        "shards" : [
                {
                        "_id" : "set1",
                        "host" : "set1/192.168.1.202:10001,192.168.1.202:10002,192.168.1.202:10003"
                },
                {
                        "_id" : "set2",
                        "host" : "set2/192.168.1.202:10011,192.168.1.202:10012,192.168.1.202:10013"
                }
        ],
        "ok" : 1
}

&gt; printShardingStatus()

--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      {
        "_id" : "set1",
        "host" : "set1/192.168.1.202:10001,192.168.1.202:10002,192.168.1.202:10003"
      }
      {
        "_id" : "set2",
        "host" : "set2/192.168.1.202:10011,192.168.1.202:10012,192.168.1.202:10013"
      }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }
        { "_id" : "test", "partitioned" : true, "primary" : "set1" }
                test.data chunks:
                        { "_id" : { $minKey : 1 } } --&gt;&gt; { "_id" : { $maxKey : 1 } } on : set1 { "t" : 1000, "i" : 0 }
</pre>
<p>&#8212;- 配置结束 &#8212;&#8212;</p>
<p>OK! 基本搞定，可以测试一下。</p>
<pre>&gt; use test
switched to db test

&gt; db.data.insert({name:1})
&gt; db.data.insert({name:2})
&gt; db.data.insert({name:3})

&gt; db.data.find()
{ "_id" : ObjectId("4c85a6d9ce93b9b1b302ebe7"), "name" : 1 }
{ "_id" : ObjectId("4c85a6dbce93b9b1b302ebe8"), "name" : 2 }
{ "_id" : ObjectId("4c85a6ddce93b9b1b302ebe9"), "name" : 3 }</pre>
<p>至于 为 Route 配置 LVS，可参考 <a title="article.asp?id=1024" href="http://www.rainsts.net/article.asp?id=1024" target="_blank">《LVS 负载均衡》</a>。       ﻿</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5310/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5310/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5310/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5310/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5310/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5310/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 8. Sharding (1)</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5313/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5313/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:12:31 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5313</guid>
		<description><![CDATA[将海量的数据水平或垂直切割，分区存储到多台服务器上是一个最基本的现实需求。从 1.6 版开始，MongoDB Sharding 总算打上了 &#8220;production-ready&#8221; 标记。 MongoDB 的数据分块称为 chunk。每个 chunk 都是 Collection 中一段连续的数据记录，通常最大尺寸是 200MB，超出则生成新的数据块。 要构建一个 MongoDB Sharding Cluster，需要三种角色： Shard Server: mongod 实例，用于存储实际的数据块。 Config Server: mongod 实例，存储了整个 Cluster Metadata，其中包括 chunk 信息。 Route Server: mongos 实例，前端路由，客户端由此接入，且让整个集群看上去像单一进程数据库。 Route 转发请求到实际的目标服务进程，并将多个结果合并回传给客户端。Route 本身并不存储任何数据和状态，仅在启动时从 Config Server 获取信息。Config Server 上的任何变动都会传递给所有的 Route Process。 在实际使用中，为了获取高可用、高 性能的集群方案，我们会将 Shard Server 和 Config Server 部署成 Replica Sets，然后用 [...]]]></description>
			<content:encoded><![CDATA[<p>将海量的数据水平或垂直切割，分区存储到多台服务器上是一个最基本的现实需求。从 1.6 版开始，<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> Sharding 总算打上了  &#8220;production-ready&#8221; 标记。</p>
<p>MongoDB 的数据分块称为 chunk。每个 chunk 都是  Collection 中一段连续的数据记录，通常最大尺寸是 200MB，超出则生成新的数据块。</p>
<p>要构建一个 MongoDB  Sharding Cluster，需要三种角色：</p>
<ul>
<li> <strong>Shard Server</strong>:  mongod 实例，用于存储实际的数据块。</li>
<li> <strong>Config Server</strong>: mongod 实例，存储了整个  Cluster Metadata，其中包括 chunk 信息。</li>
<li> <strong>Route Server</strong>: mongos  实例，前端路由，客户端由此接入，且让整个集群看上去像单一进程数据库。</li>
</ul>
<p>Route  转发请求到实际的目标服务进程，并将多个结果合并回传给客户端。Route 本身并不存储任何数据和状态，仅在启动时从 Config Server  获取信息。Config Server 上的任何变动都会传递给所有的 Route Process。<br />
<span id="more-5313"></span><br />
在实际使用中，为了获取高可用、高 性能的集群方案，我们会将 Shard Server 和 Config Server 部署成 Replica Sets，然后用 LVS 部署多个  Route。</p>
<p>我们先构建一个简单的 Sharding Cluster，以熟悉相关的配置。</p>
<p>(1) 启动 Shard  Server。</p>
<pre>$ sudo mkdir -p /var/mongodb/0
$ sudo mkdir -p /var/mongodb/1

$ sudo ./mongod --shardsvr --port 10000 --dbpath /var/mongodb/0 --fork --logpath /dev/null
forked process: 1414
all output going to: /dev/null

$ sudo ./mongod --shardsvr --port 10001 --dbpath /var/mongodb/1 --fork --logpath /dev/null
forked process: 1424
all output going to: /dev/null</pre>
<p>(2) 启动 Config Server。</p>
<pre>$ sudo mkdir -p /var/mongodb/config

$ sudo ./mongod --configsvr --port 20000 --dbpath /var/mongodb/config --fork --logpath /dev/null
forked process: 1434
all output going to: /dev/null</pre>
<p>(3) 启动 Route Process。</p>
<pre>$ sudo ./mongos --configdb localhost:20000 --fork --logpath /dev/null
forked process: 1443
all output going to: /dev/null</pre>
<p>可以用 &#8211;chunkSize 参数指定分块大小。</p>
<p>(4)  连接到 Route，开始配置。</p>
<pre>$ ./mongo

MongoDB shell version: 1.6.1
connecting to: test

&gt; use admin
switched to db admin

&gt; db.runCommand({ addshard:"localhost:10000" })
{ "shardAdded" : "shard0000", "ok" : 1 }

&gt; db.runCommand({ addshard:"localhost:10001" })
{ "shardAdded" : "shard0001", "ok" : 1 }

&gt; db.runCommand({ enablesharding:"test" })
{ "ok" : 1 }

&gt; db.runCommand({ shardcollection: "test.users", key: { _id:1 }})
{ "collectionsharded" : "test.users", "ok" : 1 }</pre>
<p>addshard: 添加  Shard Server，相关的命令还有 listshards 和 removeshard。<br />
enablesharding:  用于设置可以被分布存储的数据库。<br />
shardcollection: 用于设置具体被切块的集合名称，且必须指定 Shard  Key，系统会自动创建索引。</p>
<p>注: Sharded Collection 只能有一个 unique index，且必须是  shard key。</p>
<p>(5) 相关的管理命令。</p>
<p>listshards 命令列出所有的 Shard Server。</p>
<pre>&gt; db.runCommand({ listshards: 1 })
{
        "shards" : [
                {
                        "_id" : "shard0000",
                        "host" : "localhost:10000"
                },
                {
                        "_id" : "shard0001",
                        "host" : "localhost:10001"
                }
        ],
        "ok" : 1
}</pre>
<p>或用 printShardingStatus 命令查看 Sharding 信息。</p>
<pre>&gt; printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:10000" }
      { "_id" : "shard0001", "host" : "localhost:10001" }
  databases:
      { "_id" : "admin", "partitioned" : false, "primary" : "config" }
      { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
           test.users chunks:
               { "_id" : { $minKey : 1 } } --&gt;&gt; { "_id" : { $maxKey : 1 } }
               on : shard0000 { "t" : 1000, "i" : 0 }</pre>
<p>用  db.&lt;collection_name&gt;.stats() 可以查看具体的 Shard 存储信息 (测试数据，与前文无关)。</p>
<pre>&gt; db.users.stats()
{
     "sharded" : true,
     "ns" : "test.users",
     "count" : 1141349,
     "size" : 63914760,
     "avgObjSize" : 55.99931309354106,
     "storageSize" : 97280256,
     "nindexes" : 1,
     "nchunks" : 3,
     "shards" : {
          "shard0000" : {
               "ns" : "test.users",
               "count" : 1013555,
               "size" : 56758296,
               "avgObjSize" : 55.99922648499588,
               "storageSize" : 86089984,
               "numExtents" : 11,
               "nindexes" : 1,
               "lastExtentSize" : 20872960,
               "paddingFactor" : 1,
               "flags" : 1,
               "totalIndexSize" : 41959424,
               "indexSizes" : {
                    "_id_" : 41959424
               },
               "ok" : 1
          },
          "shard0001" : {
               "ns" : "test.users",
               "count" : 127794,
               "size" : 7156464,
               "avgObjSize" : 56,
               "storageSize" : 11182080,
               "numExtents" : 6,
               "nindexes" : 1,
               "lastExtentSize" : 8388608,
               "paddingFactor" : 1,
               "flags" : 1,
               "totalIndexSize" : 5308416,
               "indexSizes" : {
                    "_id_" : 5308416
               },
               "ok" : 1
          }
     },
     "ok" : 1
}</pre>
<p>isdbgrid 用来确认当前是否是 Sharding Cluster。</p>
<pre>&gt; db.runCommand({ isdbgrid:1 })
{ "isdbgrid" : 1, "hostname" : "yuhen-server64", "ok" : 1 }

&gt; db.runCommand({ ismaster:1 })
{ "ismaster" : 1, "msg" : "isdbgrid", "ok" : 1 }</pre>
<p>&#8212;&#8212;&#8212;  华丽的分隔线 &#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>测试一下效果：</p>
<pre>$ ipython

In [1]: from pymongo import *

In [2]: conn = Connection()

In [3]: db = conn.test

In [4]: for i in xrange(2000000):
   ...:     u = dict(name = "user" + str(i))
   ...:     print i, db.users.insert(u)

# 呼啦啦，好多东东啊，喝茶去...

In [5]: db.users.count()
Out[5]: 2000000</pre>
<p>从 test.users chunks 可以看到分块存储的范围。</p>
<pre>&gt; printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:10000" }
      { "_id" : "shard0001", "host" : "localhost:10001" }
  databases:
      { "_id" : "admin", "partitioned" : false, "primary" : "config" }
      { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
          test.users chunks:
              { "_id" : { $minKey : 1 } } --&gt;&gt; { "_id" : ObjectId("4c7...000") }
              on : shard0001 { "t" : 2000, "i" : 0 }
              { "_id" : ObjectId("4c7...000") } --&gt;&gt; { "_id" : ObjectId("4c7...d3b") }
              on : shard0000 { "t" : 3000, "i" : 1 }
              { "_id" : ObjectId("4c7...d3b") } --&gt;&gt; { "_id" : { $maxKey : 1 } }
              on : shard0001 { "t" : 3000, "i" : 0 }</pre>
<p>看看存储目录使用情况  (删除了一些信息，便于阅读)。</p>
<pre>$ du -h /var/mongodb | grep -v _tmp

1.2G    /var/mongodb
465M    /var/mongodb/0
465M    /var/mongodb/1
209M    /var/mongodb/config</pre>
<p>更详细一些 (删除了一些信息，便于阅读)。</p>
<pre>$ ls -lhR /var/mongodb

/var/mongodb:
total 12K
drwxr-xr-x 4 root root 4.0K 2010-08-23 19:21 0
drwxr-xr-x 3 root root 4.0K 2010-08-23 19:23 1
drwxr-xr-x 3 root root 4.0K 2010-08-23 18:33 config

/var/mongodb/0:
total 465M
-rwxr-xr-x 1 root root    5 2010-08-23 18:32 mongod.lock
drwxr-xr-x 3 root root 4.0K 2010-08-23 19:21 moveChunk
-rw------- 1 root root  64M 2010-08-23 19:21 test.0
-rw------- 1 root root 128M 2010-08-23 19:21 test.1
-rw------- 1 root root 256M 2010-08-23 19:14 test.2
-rw------- 1 root root  16M 2010-08-23 19:21 test.ns
drwxr-xr-x 2 root root 4.0K 2010-08-23 18:36 _tmp

/var/mongodb/1:
total 465M
-rwxr-xr-x 1 root root    5 2010-08-23 18:32 mongod.lock
-rw------- 1 root root  64M 2010-08-23 19:25 test.0
-rw------- 1 root root 128M 2010-08-23 19:25 test.1
-rw------- 1 root root 256M 2010-08-23 19:23 test.2
-rw------- 1 root root  16M 2010-08-23 19:25 test.ns
drwxr-xr-x 2 root root 4.0K 2010-08-23 19:21 _tmp

/var/mongodb/config:
total 209M
-rw------- 1 root root  64M 2010-08-23 19:26 config.0
-rw------- 1 root root 128M 2010-08-23 18:33 config.1
-rw------- 1 root root  16M 2010-08-23 19:21 config.ns
-rw-r--r-- 1 root root  41K 2010-08-23 19:22 diaglog.4c724e45
-rwxr-xr-x 1 root root    5 2010-08-23 18:32 mongod.lock
drwxr-xr-x 2 root root 4.0K 2010-08-23 18:36 _tmp</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5313/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5313/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5313/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5313/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5313/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5313/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 7. Replication (2)</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5308/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5308/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:10:54 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5308</guid>
		<description><![CDATA[2. Master/Slave Master/Slave 是一种典型的备份方案，MongoDB 支持 &#8220;One Master Multi Salver&#8221; 和 &#8220;Multi Master One Slave&#8221; 等多种部署方式。 先从简单的 &#8220;镜像备份&#8221; 开始。 $ sudo mkdir -p /var/mongodb/0 $ sudo mkdir -p /var/mongodb/1 $ sudo ./mongod --fork --logpath /dev/null --dbpath /var/mongodb/0 --master forked process: 1388 all output going to: /dev/null $ sudo ./mongod --fork --logpath /dev/null --dbpath /var/mongodb/1 --port 27018 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>2. Master/Slave</strong></p>
<p>Master/Slave 是一种典型的备份方案，<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 支持 &#8220;One  Master Multi Salver&#8221; 和 &#8220;Multi Master One Slave&#8221; 等多种部署方式。</p>
<p>先从简单的  &#8220;镜像备份&#8221; 开始。</p>
<pre>$ sudo mkdir -p /var/mongodb/0
$ sudo mkdir -p /var/mongodb/1

$ sudo ./mongod --fork --logpath /dev/null --dbpath /var/mongodb/0 --master
forked process: 1388
all output going to: /dev/null

$ sudo ./mongod --fork --logpath /dev/null --dbpath /var/mongodb/1 --port 27018 --slave --source localhost:27017 --autoresync
forked process: 1401
all output going to: /dev/null</pre>
<p>autoresync  参数会在系统发生意外情况造成主从数据不同步时，自动启动复制操作 (同步复制 10 分钟内仅执行一次)。除此之外，还可以用  &#8211;slavedelay 设定更新频率(秒)。<br />
<span id="more-5308"></span><br />
使用  isMaster、printReplicationInfo、printSlaveReplicationInfo 等命令获取相关状态信息。</p>
<pre>$ ./mongo 

&gt; db.isMaster()
{ "ismaster" : true, "ok" : 1 }

&gt; db.printReplicationInfo()
configured oplog size:   990MB
log length start to end: 1164secs (0.32hrs)
oplog first event time:  Mon Aug 23 2010 12:23:54 GMT+0800 (CST)
oplog last event time:   Mon Aug 23 2010 12:43:18 GMT+0800 (CST)
now:                     Mon Aug 23 2010 12:43:24 GMT+0800 (CST)

$ ./mongo localhost:27018

&gt; db.isMaster()
{ "ismaster" : false, "ok" : 1 }

&gt; db.printSlaveReplicationInfo()
source:   localhost:27017
         syncedTo: Mon Aug 23 2010 12:43:58 GMT+0800 (CST)
                 = 10secs ago (0hrs)

&gt; show dbs
admin
local
test

&gt; use local
switched to db local

&gt; show collections
me
pair.sync
sources
system.indexes

&gt; db.sources.find()
{ "_id" : ObjectId("4c71f8178d806ad3f54dd89a"), "host" : "localhost:27017", "source" : "main", "syncedTo" : { "t" : 1282538738000, "i" : 1 }, "localLogTs" : { "t" : 0, "i" : 0 } }</pre>
<p>Slave  的配置信息保存在 local.sources 中。</p>
<p>通常我们会使用主从方案实现读写分离，但需要设置 Slave_OK。</p>
<pre>$ ipython

IPython 0.10 -- An enhanced Interactive Python.

In [1]: from pymongo import *

In [2]: m_conn = Connection()

In [3]: s_conn = Connection(host="localhost:27018", slave_okay=True)

In [4]: m_db = m_conn.test

In [5]: s_db = s_conn.test

# ----------------------------------------- #

In [6]: m_db.users.insert({"name":"user3"})
Out[6]: ObjectId('4c71feb0499b140632000000')

In [7]: s_db.users.find_one({"name":"user3"}) # 数据被复制到 Slave
Out[7]: {u'_id': ObjectId('4c71feb0499b140632000000'), u'name': u'user3'}

In [8]: m_db.users.remove({"name":"user3"}) # 删除 Master 数据

In [9]: for u in m_db.users.find(): print u
   ....:
{u'_id': ObjectId('4c71fa4d5e01e1ba6d62398f'), u'name': u'user1'}

In [10]: for u in s_db.users.find(): print u # Slave 记录被同步删除
   ....:
{u'_id': ObjectId('4c71fa4d5e01e1ba6d62398f'), u'name': u'user1'}

# ----------------------------------------- #

In [11]: s_db.users.insert({"name":"userx"}) # 在 Slave 插入数据
Out[11]: ObjectId('4c71ff2c499b140632000001')

In [12]: for u in m_db.users.find(): print u # Master 上无该数据
   ....:
{u'_id': ObjectId('4c71fa4d5e01e1ba6d62398f'), u'name': u'user1'}

In [13]: for u in s_db.users.find(): print u # Slave 同样没有
   ....:
{u'_id': ObjectId('4c71fa4d5e01e1ba6d62398f'), u'name': u'user1'}
</pre>
<p>可见 Slave 读操作正常，但写无效果。</p>
<p>我们还可以部署 &#8220;One Slave Two Master&#8221;  方案。</p>
<pre>$ sudo mkdir -p /var/mongodb/m1
$ sudo mkdir -p /var/mongodb/m2
$ sudo mkdir -p /var/mongodb/s

$ sudo ./mongod --fork --dbpath /var/mongodb/m1 --logpath /dev/null --master
forked process: 1616
all output going to: /dev/null

$ sudo ./mongod --fork --dbpath /var/mongodb/m2 --logpath /dev/null --port 27018 --master
forked process: 1627
all output going to: /dev/null

$ sudo ./mongod --fork --dbpath /var/mongodb/s --logpath /dev/null --port 27019 --slave
forked process: 1638
all output going to: /dev/null</pre>
<p>连接 Slave，添加配置。</p>
<pre>$ ./mongo localhost:27019

MongoDB shell version: 1.6.1
connecting to: localhost:27019/test

&gt; use local
switched to db local

&gt; db.sources.insert({host:"localhost:27017"})
&gt; db.sources.insert({host:"localhost:27018"})

&gt; db.printSlaveReplicationInfo()
source:   localhost:27017
         syncedTo: Mon Aug 23 2010 13:06:03 GMT+0800 (CST)
                 = 17secs ago (0hrs)
source:   localhost:27018
         doing initial sync</pre>
<p>在两台 Master 上添加数据，查看复制效果。</p>
<pre>$ ./mongo localhost:27017

MongoDB shell version: 1.6.1
connecting to: localhost:27017/test

&gt; use db1
switched to db db1

&gt; db.users.insert({name:"user1"})
&gt; db.users.insert({name:"user2"})

&gt; db.users.find()
{ "_id" : ObjectId("4c720211ade34e85c5380eab"), "name" : "user1" }
{ "_id" : ObjectId("4c720214ade34e85c5380eac"), "name" : "user2" }

&gt; exit
bye</pre>
<pre>$ ./mongo localhost:27018

MongoDB shell version: 1.6.1
connecting to: localhost:27018/test

&gt; use db2
switched to db db2

&gt; db.blogs.insert({title:"aaa"})
&gt; db.blogs.insert({title:"bbb"})
&gt; db.blogs.insert({title:"ccc"})

&gt; db.blogs.find()
{ "_id" : ObjectId("4c720236f24118cb2f59218d"), "title" : "aaa" }
{ "_id" : ObjectId("4c720239f24118cb2f59218e"), "title" : "bbb" }
{ "_id" : ObjectId("4c72023cf24118cb2f59218f"), "title" : "ccc" }

&gt; exit
bye</pre>
<pre>$ ./mongo localhost:27019

MongoDB shell version: 1.6.1
connecting to: localhost:27019/test

&gt; show dbs
admin
db1
db2
local

&gt; use db1
switched to db db1

&gt; db.users.find()
{ "_id" : ObjectId("4c720211ade34e85c5380eab"), "name" : "user1" }
{ "_id" : ObjectId("4c720214ade34e85c5380eac"), "name" : "user2" }

&gt; use db2
switched to db db2

&gt; db.blogs.find()
{ "_id" : ObjectId("4c720236f24118cb2f59218d"), "title" : "aaa" }
{ "_id" : ObjectId("4c720239f24118cb2f59218e"), "title" : "bbb" }
{ "_id" : ObjectId("4c72023cf24118cb2f59218f"), "title" : "ccc" }
&gt;</pre>
<p>一切正常。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5308/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5308/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5308/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5308/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5308/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5308/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 7. Replication (1)</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5307/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5307/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:10:09 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5307</guid>
		<description><![CDATA[最新的 1.6 版总算提供了 Replica Sets，比起有点莫名其妙的 Replica Pairs，这才是高可用集群所需要的。 1. Replica Sets Replica Sets 使用 n 个 Mongod 节点，构建具备自动容错转移(auto-failover)、自动恢复(auto-recovery) 的高可用方案。通常使用 3 个 mongod 实例，或者 2 mongod + 1 arbiter 方案。 (1) 首先启动所需的 Mongod 节点。注意使用 replSet 参数指定 Sets Name。 $ sudo mkdir -p /var/mongodb/0 $ sudo mkdir -p /var/mongodb/1 $ sudo mkdir -p /var/mongodb/2 $ sudo ./mongod --fork [...]]]></description>
			<content:encoded><![CDATA[<p>最新的 1.6 版总算提供了 Replica Sets，比起有点莫名其妙的 Replica Pairs，这才是高可用集群所需要的。</p>
<p><strong>1.  Replica Sets</strong></p>
<p>Replica Sets 使用 n 个 Mongod  节点，构建具备自动容错转移(auto-failover)、自动恢复(auto-recovery) 的高可用方案。通常使用 3 个 mongod  实例，或者 2 mongod + 1 arbiter 方案。</p>
<p>(1) 首先启动所需的 Mongod 节点。注意使用 replSet  参数指定 Sets Name。</p>
<pre>$ sudo mkdir -p /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/0
$ sudo mkdir -p /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/1
$ sudo mkdir -p /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/2

$ sudo ./mongod --fork --logpath /dev/null --dbpath /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/0 --port 27017 --replSet myset
forked process: 1166
all output going to: /dev/null

$ sudo ./mongod --fork --logpath /dev/null --dbpath /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/1 --port 27018 --replSet myset
forked process: 1173
all output going to: /dev/null

$ sudo ./mongod --fork --logpath /dev/null --dbpath /var/<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">mongodb</a>/2 --port 27019 --replSet myset
forked process: 1180
all output going to: /dev/null</pre>
<p><span id="more-5307"></span><br />
(2) 使用 mongo 配置 Replica Sets。</p>
<pre>$ ./mongo

MongoDB shell version: 1.6.1
connecting to: test

&gt; cfg = { _id: "myset", members: [
... { _id:0, host:"localhost:27017" },
... { _id:1, host:"localhost:27018" },
... { _id:2, host:"localhost:27019" }
... ]}

&gt; rs.initiate(cfg)
{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}

&gt; rs.conf()
{
        "_id" : "myset",
        "version" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "host" : "localhost:27017"
                },
                {
                        "_id" : 1,
                        "host" : "localhost:27018"
                },
                {
                        "_id" : 2,
                        "host" : "localhost:27019"
                }
        ]
}</pre>
<p>如此 Replica Sets 就算配置成功。</p>
<p>相关配置数据保存在 local 数据库中。</p>
<pre>&gt; show dbs
admin
local

&gt; use local
switched to db local

&gt; show collections
oplog.rs
slaves
system.indexes
system.replset

&gt; db.system.replset.find()
{ "_id" : "myset", "version" : 1, "members" : [
        {
                "_id" : 0,
                "host" : "localhost:27017"
        },
        {
                "_id" : 1,
                "host" : "localhost:27018"
        },
        {
                "_id" : 2,
                "host" : "localhost:27019"
        }
] }</pre>
<p>oplog.rs 是一个固定长度的 capped collection，用于记录 Replica Sets 操作日志。</p>
<p>(3)  可以用 isMaster 和 status 命令查看 Replica Sets 状态。</p>
<pre>&gt; rs.isMaster()
{
        "ismaster" : true,
        "secondary" : false,
        "hosts" : [
                "localhost:27017",
                "localhost:27019",
                "localhost:27018"
        ],
        "ok" : 1
}

&gt; rs.status()
{
        "set" : "myset",
        "date" : "Sat Aug 21 2010 15:21:13 GMT+0800 (CST)",
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "yuhen-server64:27017",
                        "health" : 1,
                        "state" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27018",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 280,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:21:11 GMT+0800 (CST)"
                },
                {
                        "_id" : 2,
                        "name" : "localhost:27019",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 284,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:21:11 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}</pre>
<p>在同一时刻，每组 Replica Sets 只有一个  Primary，用于接受写操作。而后会异步复制到其他成员数据库中。一旦 primary 死掉，会自动投票选出接任的 primary  来，原服务器恢复后成为普通成员。如果数据尚未从先前的 primary 复制到成员服务器，有可能会丢失数据。</p>
<p>(4)  为了观察数据复制和容错迁移，我们可以开几个终端，在前台运行 mongod。</p>
<pre>$ sudo ./mongod --port 27017 --dbpath /var/mongodb/0 --replSet myset</pre>
<p>在  mongo 中向 primary (27017) 插入数据。</p>
<pre>&gt; use test
switched to db test

&gt; db.users.insert({name:"user1"})</pre>
<p>会在所有 mongod 输出记录中看到相关信息。</p>
<pre># 27017 #
Sat Aug 21 15:35:50 [conn2] building new index on { _id: 1 } for test.users
Sat Aug 21 15:35:50 [conn2] Buildindex test.users idxNo:0 { name: "_id_", ns: "test.users", key: { _id: 1 } }
Sat Aug 21 15:35:50 [conn2] done for 0 records 0.01secs
Sat Aug 21 15:35:50 [conn12] getmore local.oplog.rs cid:4961370576520295111 getMore: { ts: { $gte: new Date(5507762976880328705) } }  bytes:118 nreturned:1 3782ms
Sat Aug 21 15:35:50 [conn2] insert test.users 1029ms

# 27018 #
Sat Aug 21 15:35:51 [rs_sync] building new index on { _id: 1 } for test.users
Sat Aug 21 15:35:51 [rs_sync] Buildindex test.users idxNo:0 { name: "_id_", ns: "test.users", key: { _id: 1 } }

# 27019 #
Sat Aug 21 15:35:51 [rs_sync] building new index on { _id: 1 } for test.users
Sat Aug 21 15:35:51 [rs_sync] Buildindex test.users idxNo:0 { name: "_id_", ns: "test.users", key: { _id: 1 } }</pre>
<p>我 们用 CTRL + C 关掉 primary mongd。</p>
<pre># 27018 #
Sat Aug 21 15:40:16 [ReplSetHealthPollTask] replSet info localhost:27017 is now down (or slow to respond)
Sat Aug 21 15:40:27 [rs_sync] replSet SECONDARY

# 27019 #
Sat Aug 21 15:40:16 [ReplSetHealthPollTask] replSet info localhost:27017 is now down (or slow to respond)
Sat Aug 21 15:40:16 [rs_sync] replSet syncThread: 10278 dbclient error communicating with server
Sat Aug 21 15:40:16 [rs Manager] replSet info electSelf 2
Sat Aug 21 15:40:16 [rs Manager] replSet PRIMARY</pre>
<p>Mongod 27019  被选为 Primary。</p>
<p>因为 27107 的 socket 关闭，所以 mongo 需要重新连接。</p>
<pre>$ ./mongo localhost:27019

MongoDB shell version: 1.6.1
connecting to: localhost:27018/test

&gt; rs.status()
{
        "set" : "myset",
        "date" : "Sat Aug 21 2010 15:41:40 GMT+0800 (CST)",
        "myState" : 2,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27017",
                        "health" : 0,
                        "state" : 1,
                        "uptime" : 0,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:40:14 GMT+0800 (CST)",
                        "errmsg" : "connect/transport error"
                },
                {
                        "_id" : 1,
                        "name" : "yuhen-server64:27018",
                        "health" : 1,
                        "state" : 2,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "localhost:27019",
                        "health" : 1,
                        "state" : 1,
                        "uptime" : 486,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:41:38 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}</pre>
<p>查询先前插入的记录正常。</p>
<pre>&gt; db.users.find()
{ "_id" : ObjectId("4c6f81d58e4719f03d5ccc65"), "name" : "user1" }</pre>
<p>我 们也可以将 mongo 连接到 27018，不过无法查询数据。</p>
<p>重新启动 27017。</p>
<pre># 27017 #
Sat Aug 21 15:44:54 [rs Manager] replSet can't see a majority, will not try to elect self
Sat Aug 21 15:44:56 [ReplSetHealthPollTask] replSet info localhost:27019 is now up
Sat Aug 21 15:44:56 [ReplSetHealthPollTask] replSet info localhost:27018 is now up
Sat Aug 21 15:44:56 [rs_sync] building new index on { _id: 1 } for local.me
Sat Aug 21 15:44:56 [rs_sync] Buildindex local.me idxNo:0 { name: "_id_", ns: "local.me", key: { _id: 1 } }
Sat Aug 21 15:44:56 [rs_sync] done for 0 records 0.002secs
Sat Aug 21 15:44:56 [rs_sync] replSet SECONDARY

# 27018 #
Sat Aug 21 15:44:55 [ReplSetHealthPollTask] replSet info localhost:27017 is now up

# 27019 #
Sat Aug 21 15:44:54 [ReplSetHealthPollTask] replSet info localhost:27017 is now up</pre>
<p>rs.status  中 heartbeat 恢复正常，但不再是 Primary。</p>
<pre>&gt; rs.status()
{
        "set" : "myset",
        "date" : "Sat Aug 21 2010 15:46:44 GMT+0800 (CST)",
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27017",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 110,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:46:44 GMT+0800 (CST)"
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27018",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 790,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:46:44 GMT+0800 (CST)"
                },
                {
                        "_id" : 2,
                        "name" : "yuhen-server64:27019",
                        "health" : 1,
                        "state" : 1,
                        "self" : true
                }
        ],
        "ok" : 1
}</pre>
<p>(5) 我们还可以在运行时添加成员。</p>
<pre>$ sudo ./mongod --fork --port 27020 --dbpath /var/mongodb/3 --logpath /dev/null --replSet myset
forked process: 2139
all output going to: /dev/null</pre>
<p>注意: 必须连接到 primary 才能添加成员。</p>
<pre>$ ./mongo localhost:27019
MongoDB shell version: 1.6.1
connecting to: localhost:27020/test

&gt; rs.add("localhost:27029")
{ "ok" : 1 }

&gt; rs.conf()
{
        "_id" : "myset",
        "version" : 2,
        "members" : [
                {
                        "_id" : 0,
                        "host" : "localhost:27017"
                },
                {
                        "_id" : 1,
                        "host" : "localhost:27018"
                },
                {
                        "_id" : 2,
                        "host" : "localhost:27019"
                },
                {
                        "_id" : 3,
                        "host" : "localhost:27020"
                }
        ]
}</pre>
<p>查看状态。</p>
<pre>&gt; rs.status()
{
        "set" : "myset",
        "date" : "Sat Aug 21 2010 15:52:54 GMT+0800 (CST)",
        "myState" : 2,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "localhost:27017",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 94,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:52:54 GMT+0800 (CST)"
                },
                {
                        "_id" : 1,
                        "name" : "localhost:27018",
                        "health" : 1,
                        "state" : 1,
                        "uptime" : 94,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:52:54 GMT+0800 (CST)"
                },
                {
                        "_id" : 2,
                        "name" : "yuhen-server64:27019",
                        "health" : 1,
                        "state" : 2,
                        "self" : true
                },
                {
                        "_id" : 3,
                        "name" : "localhost:27020",
                        "health" : 1,
                        "state" : 2,
                        "uptime" : 92,
                        "lastHeartbeat" : "Sat Aug 21 2010 15:52:54 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}</pre>
<p>(6) 从客户端连接 Replica Sets，需要 drivers 支持。</p>
<pre>$ ipython

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
IPython 0.10 -- An enhanced Interactive Python.

In [1]: import pymongo

In [2]: conn = pymongo.Connection(host = ["localhost:27017", "localhost:27018", "localhost:27019", "localhost:27020"])

In [3]: db = conn.test

In [4]: for u in db.users.find(): print u
   ...:
{u'_id': ObjectId('4c6f81d58e4719f03d5ccc65'), u'name': u'user1'}
{u'_id': ObjectId('4c6f82ad8e4719f03d5ccc66'), u'name': u'user2'}

In [5]: db.users.insert({"name":"user3"})
Out[5]: ObjectId('4c6f8872499b1408b7000000')</pre>
<p>从其他终端关掉  primary，看看效果。</p>
<pre>In [6]: db.users.count()
---------------------------------------------------------------------------
AutoReconnect                             Traceback (most recent call last)

AutoReconnect: connection closed</pre>
<p>由于连接被中断，引发异常也很正常，不过 pymongo  会自动重新连接，再次操作时一切正常。</p>
<pre>In [7]: db.users.count()
Out[7]: 3

In [8]: for u in db.users.find(): print u
   ...:
{u'_id': ObjectId('4c6f81d58e4719f03d5ccc65'), u'name': u'user1'}
{u'_id': ObjectId('4c6f82ad8e4719f03d5ccc66'), u'name': u'user2'}
{u'_id': ObjectId('4c6f8872499b1408b7000000'), u'name': u'user3'}</pre>
<p>因 此编码时切记需要做异常保护。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5307/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5307/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5307/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5307/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5307/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5307/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 6. Optimization</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5302/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5302/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:08:13 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5302</guid>
		<description><![CDATA[1. Profiler MongoDB 自带 Profiler，可以非常方便地记录下所有耗时过长操作，以便于调优。 &#62; db.setProfilingLevel(n) n: 0: Off; 1: Log Slow Operations; 2: Log All Operations. 通常我们只关心 Slow Operation，Level 1 默认记录 &#62;100ms 的操作，当然我们也可以自己调整 &#8220;db.setProfilingLevel(2, 300)&#8221;。 Profiler 信息保存在 system.profile (Capped Collection) 中。 准备 1000000 条数据测试一下。 &#62;&#62;&#62; from pymongo import * &#62;&#62;&#62; from random import randint &#62;&#62;&#62; conn = Connection() &#62;&#62;&#62; db = conn.blog &#62;&#62;&#62; [...]]]></description>
			<content:encoded><![CDATA[<p><strong>1. Profiler</strong></p>
<p><a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 自带 Profiler，可以非常方便地记录下所有耗时过长操作，以便于调优。</p>
<pre>&gt; db.setProfilingLevel(n)

n:
   0: Off;
   1: Log Slow Operations;
   2: Log All Operations.</pre>
<p>通常我们只关心 Slow Operation，Level 1 默认记录  &gt;100ms 的操作，当然我们也可以自己调整 &#8220;db.setProfilingLevel(2, 300)&#8221;。<br />
Profiler  信息保存在 system.profile (Capped Collection) 中。</p>
<p>准备 1000000 条数据测试一下。</p>
<pre>&gt;&gt;&gt; from pymongo import *
&gt;&gt;&gt; from random import randint
&gt;&gt;&gt; conn = Connection()
&gt;&gt;&gt; db = conn.blog

&gt;&gt;&gt; for i in xrange(1000000):
    u = dict(name = "user" + str(i), age = randint(10, 90))
    db.users.insert(u)</pre>
<p>开始调优操作。<br />
<span id="more-5302"></span></p>
<pre>&gt; db.setProfilingLevel(1)
{ "was" : 0, "ok" : 1 }

&gt; db.users.find().sort({age:-1}).limit(10000)
{ "_id" : ObjectId("4c50dc07499b1404c60f42e5"), "age" : 90, "name" : "user165" }
{ "_id" : ObjectId("4c50dc07499b1404c60f42e8"), "age" : 90, "name" : "user168" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4350"), "age" : 90, "name" : "user272" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4358"), "age" : 90, "name" : "user280" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4375"), "age" : 90, "name" : "user309" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4433"), "age" : 90, "name" : "user499" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4480"), "age" : 90, "name" : "user576" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4484"), "age" : 90, "name" : "user580" }
{ "_id" : ObjectId("4c50dc07499b1404c60f44cf"), "age" : 90, "name" : "user655" }
{ "_id" : ObjectId("4c50dc07499b1404c60f44fb"), "age" : 90, "name" : "user699" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4517"), "age" : 90, "name" : "user727" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4688"), "age" : 90, "name" : "user1096" }
{ "_id" : ObjectId("4c50dc07499b1404c60f46a8"), "age" : 90, "name" : "user1128" }
{ "_id" : ObjectId("4c50dc07499b1404c60f46ae"), "age" : 90, "name" : "user1134" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4740"), "age" : 90, "name" : "user1280" }
{ "_id" : ObjectId("4c50dc07499b1404c60f479b"), "age" : 90, "name" : "user1371" }
{ "_id" : ObjectId("4c50dc07499b1404c60f479d"), "age" : 90, "name" : "user1373" }
{ "_id" : ObjectId("4c50dc07499b1404c60f480f"), "age" : 90, "name" : "user1487" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4842"), "age" : 90, "name" : "user1538" }
{ "_id" : ObjectId("4c50dc07499b1404c60f4844"), "age" : 90, "name" : "user1540" }
has more

&gt; db.system.profile.find()
{
    "ts" : "Thu Jul 29 2010 09:47:47 GMT+0800 (CST)",
    "info" : "query blog.users
        ntoreturn:10000 scanAndOrder
        reslen:518677
        nscanned:1000000
        query: { query: {}, orderby: { age: -1.0 } }
        nreturned:10000 1443ms",
    "millis" : 1443
}</pre>
<p>system.profile 中记录下一条耗时过长的操作。</p>
<ul>
<li> ts:  操作执行时间。</li>
<li> info: 操作详细信息。</li>
<li> info.query: 查询目标(数据库.集合)。</li>
<li> info.ntoreturn: 客户端期望返回的文档数量。</li>
<li> info.nscanned: 服务器实际扫描的文档数量。</li>
<li> info.reslen: 查询结果字节长度。</li>
<li> info.nreturnned: 查询返回文档数。</li>
<li> millis: 操作耗时(毫秒)。</li>
</ul>
<p>很显然，该操作扫描的文档过多(info.nscanned)，通常是没有使用索引造成的。我们 用 explain() 看看服务器如何执行执行该命令。</p>
<pre>&gt; db.users.find().sort({age:-1}).limit(10000).explain()
{
        "cursor" : "BasicCursor",
        "nscanned" : 1000000,
        "nscannedObjects" : 1000000,
        "n" : 10000,
        "scanAndOrder" : true,
        "millis" : 1412,
        "indexBounds" : {

        }
}</pre>
<p>没有索引自然很慢了，建个索引看看效果。</p>
<pre>&gt; db.users.ensureIndex({age:-1})

&gt; db.users.find().sort({age:-1}).limit(10000).explain()
{
        "cursor" : "BtreeCursor age_-1",
        "nscanned" : 10000,
        "nscannedObjects" : 10000,
        "n" : 10000,
        "millis" : 211,
        "indexBounds" : {
                "age" : [
                        [
                                {
                                        "$maxElement" : 1
                                },
                                {
                                        "$minElement" : 1
                                }
                        ]
                ]
        }
}</pre>
<p>速度提升非常明显。最后别忘了 Profiler 本身也会影响服务器性能，不用的时候要关掉。</p>
<pre>&gt; db.setProfilingLevel(0)
{ "was" : 1, "ok" : 1 }</pre>
<p>除了使用 setProfilingLevel 命令外，也可以在 mongod  参数中启用 profiler，不推荐。</p>
<pre>--profile arg             0=off 1=slow, 2=all
--slowms arg (=100)       value of slow for profile and console log</pre>
<p><strong>2.  Optimization</strong></p>
<p>优化建议:</p>
<ul>
<li> 如果 nscanned 远大于  nreturned，那么需要使用索引。</li>
<li> 如果 reslen 返回字节非常大，那么考虑只获取所需的字段。</li>
<li> 执行  update 操作时同样检查一下 nscanned，并使用索引减少文档扫描数量。</li>
<li> 使用 db.eval()  在服务端执行某些统计操作。</li>
<li> 减少返回文档数量，使用 skip &amp; limit 分页。</li>
</ul>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5302/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5302/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5302/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5302/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5302/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5302/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 5. Admin</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5301/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5301/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:06:39 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5301</guid>
		<description><![CDATA[Mongod 是 MongoDB 核心程序，通常情况下我们只需折腾该程序即可。 1. dbpath &#38; port 默 认数据存储路径是 /data/db，默认端口 27017，默认 HTTP 端口 28017。用 &#8211;dbpath 和 &#8211;port 改吧。 $ sudo ./mongod --dbpath /var/mongodb --port 1234 Sat Jul 24 22:58:50 MongoDB starting : pid=1683 port=1234 dbpath=/var/mongodb 64-bit ** NOTE: This is a development version (1.5.4) of MongoDB. ** Not recommended for production. Sat Jul 24 [...]]]></description>
			<content:encoded><![CDATA[<p>Mongod 是 <a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 核心程序，通常情况下我们只需折腾该程序即可。</p>
<p><strong>1. dbpath &amp; port</strong></p>
<p>默 认数据存储路径是 /data/db，默认端口 27017，默认 HTTP 端口 28017。用 &#8211;dbpath 和 &#8211;port 改吧。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --port 1234

Sat Jul 24 22:58:50 MongoDB starting : pid=1683 port=1234 dbpath=/var/mongodb 64-bit

** NOTE: This is a development version (1.5.4) of MongoDB.
**       Not recommended for production.

Sat Jul 24 22:58:50 db version v1.5.4, pdfile version 4.5
Sat Jul 24 22:58:50 git version: 6c1361df41d9cabf9026364427a7df44b3c304fd
Sat Jul 24 22:58:50 sys info: Linux domU-12-31-39-06-79-A1 2.6.21.7-2.ec2.v1.2.fc8xen
[initandlisten] Sat Jul 24 22:58:50 waiting for connections on port 1234
[websvr] Sat Jul 24 22:58:50 web admin interface listening on port 2234</pre>
<p>从启动信息可以看到  Web 管理端口 2234，CTRL + C 即可停止该进程。&#8211;bind_ip 用于设定监听绑定 IP。<br />
<span id="more-5301"></span></p>
<pre>Sat Jul 24 22:58:53 got kill or ctrl c signal 2 (Interrupt), will terminate after current cmd ends
[interruptThread] Sat Jul 24 22:58:53 now exiting
Sat Jul 24 22:58:53  dbexit:
[interruptThread] Sat Jul 24 22:58:53    shutdown: going to close listening sockets...
[interruptThread] Sat Jul 24 22:58:53    going to close listening socket: 5
[interruptThread] Sat Jul 24 22:58:53    going to close listening socket: 6
[interruptThread] Sat Jul 24 22:58:53    going to close listening socket: 7
[interruptThread] Sat Jul 24 22:58:53    going to close listening socket: 8
[interruptThread] Sat Jul 24 22:58:53    shutdown: going to flush oplog...
[interruptThread] Sat Jul 24 22:58:53    shutdown: going to close sockets...
[interruptThread] Sat Jul 24 22:58:53    shutdown: waiting for fs preallocator...
[interruptThread] Sat Jul 24 22:58:53    shutdown: closing all files...
Sat Jul 24 22:58:53      closeAllFiles() finished
[interruptThread] Sat Jul 24 22:58:53    shutdown: removing fs lock...
Sat Jul 24 22:58:53  dbexit: really exiting now</pre>
<p>默认情况下，所有的 DB  都存储到 &#8211;dbpath 指定的目录中。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --fork --logpath /dev/null
forked process: 2018
all output going to: /dev/null

$ ./mongo
MongoDB shell version: 1.5.4
connecting to: test
&gt; db.c1.insert({a:1})
&gt; use blog
switched to db blog
&gt; db.c2.insert({b:1})
&gt; exit
bye

$ ls /var/mongodb/
blog  blog.0  blog.1  blog.ns  mongod.lock  test  test.0  test.1  test.ns  _tmp

$ sudo kill -INT 2018</pre>
<p>可以用 &#8211;directoryperdb 参数让系统为每个 DB  创建一个独立子目录。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --fork --logpath /dev/null --directoryperdb
forked process: 2060
all output going to: /dev/null

$ ./mongo
MongoDB shell version: 1.5.4
connecting to: test
&gt; db.c1.insert({a:1})
&gt; use blog
switched to db blog
&gt; db.c2.insert({b:1})
&gt; exit
bye

$ ls -R /var/mongodb
/var/mongodb:
blog  mongod.lock  test  _tmp

/var/mongodb/blog:
blog.0  blog.1  blog.ns

/var/mongodb/test:
test.0  test.1  test.ns

/var/mongodb/_tmp:</pre>
<p><strong>2. daemon</strong></p>
<p>如果想以 Daemon  方式运行，需要同时使用 &#8211;fork、&#8211;logpath 参数。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --fork --logpath /dev/null

forked process: 1797
all output going to: /dev/null</pre>
<p>想要停止服务，可以发送 INT 或 TERM 信号。</p>
<pre>$ sudo kill -INT 1797</pre>
<p>或 者使用 mongo 连接到服务器，然后执行 shutdownServer 命令。</p>
<pre>$ ./mongo

MongoDB shell version: 1.5.4
connecting to: test

&gt; use admin
switched to db admin

&gt; db.shutdownServer()
Sat Jul 24 23:11:36 query failed : admin.$cmd { shutdown: 1.0 } to: 127.0.0.1
server should be down...
Sat Jul 24 23:11:36 trying reconnect to 127.0.0.1
Sat Jul 24 23:11:36 reconnect 127.0.0.1 failed couldn't connect to server {ip: "127.0.0.1", port: 27017}
Sat Jul 24 23:11:36 MessagingPort say send() errno:9 Bad file descriptor 127.0.0.1:27017
Sat Jul 24 23:11:36 Error: error doing query: unknown (anon):1421

&gt; exit
bye</pre>
<p><strong>3. logging</strong></p>
<p>与 Logging 有关的参数除了 &#8211;logpath，还有  &#8211;logappend 和 &#8211;verbose。</p>
<p>默认情况下，Logging 是覆盖模式(overwrite)，通过  &#8211;logappend 可以添加模式记录日志。<br />
参数 &#8211;verbose 设置记录等级，相当于 -v，更多的级别包括 -vv 直到  -vvvvv。与之相对的是  &#8211;quiet，生成最少的日志信息。<br />
还可以用 &#8211;cpu 记录 CPU 的相关信息。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb -vvvvv

Sun Jul 25 00:41:22 MongoDB starting : pid=2113 port=27017 dbpath=/var/mongodb 64-bit

** NOTE: This is a development version (1.5.4) of MongoDB.
**       Not recommended for production.

Sun Jul 25 00:41:22 db version v1.5.4, pdfile version 4.5
Sun Jul 25 00:41:22 git version: 6c1361df41d9cabf9026364427a7df44b3c304fd
Sun Jul 25 00:41:22 sys info: Linux domU-12-31-39-06-79-A1 2.6.21.7-2.ec2.v1.2.fc8xen #1 ...
[initandlisten] Sun Jul 25 00:41:22 query: local.system.namespaces{ name: /^local.temp./ }
[initandlisten] Sun Jul 25 00:41:22 Accessing: local for the first time
[initandlisten] Sun Jul 25 00:41:22    used cursor: 0x1300d30
[initandlisten] Sun Jul 25 00:41:22 query local.system.namespaces reslen:36 nreturned:0 0ms
[initandlisten] Sun Jul 25 00:41:22 enter repairDatabases
[initandlisten] Sun Jul 25 00:41:22 done repairDatabases
[initandlisten] Sun Jul 25 00:41:22 waiting for connections on port 27017
[websvr] Sun Jul 25 00:41:22 web admin interface listening on port 28017
[initandlisten] Sun Jul 25 00:41:30 connection accepted from 127.0.0.1:46032 #1
[conn1] Sun Jul 25 00:41:30 query: admin.$cmd{ whatsmyuri: 1 }
[conn1] Sun Jul 25 00:41:30 run command admin.$cmd { whatsmyuri: 1 }
[conn1] Sun Jul 25 00:41:30 query admin.$cmd ntoreturn:1 command: { whatsmyuri: 1 } reslen:71 0ms
[DataFileSync] Sun Jul 25 00:42:22 flushing mmap took 0ms
[DataFileSync] Sun Jul 25 00:43:22 flushing mmap took 0ms
[DataFileSync] Sun Jul 25 00:44:22 flushing mmap took 0ms

^C

Sun Jul 25 00:45:22 got kill or ctrl c signal 2 (Interrupt), will terminate after current cmd ends
[interruptThread] Sun Jul 25 00:45:22 now exiting
Sun Jul 25 00:45:22  dbexit:
[interruptThread] Sun Jul 25 00:45:22    shutdown: going to close listening sockets...
[interruptThread] Sun Jul 25 00:45:22    going to close listening socket: 5
[interruptThread] Sun Jul 25 00:45:22    going to close listening socket: 6
[interruptThread] Sun Jul 25 00:45:22    going to close listening socket: 7
[interruptThread] Sun Jul 25 00:45:22    going to close listening socket: 8
[interruptThread] Sun Jul 25 00:45:22    shutdown: going to flush oplog...
[interruptThread] Sun Jul 25 00:45:22    shutdown: going to close sockets...
[interruptThread] Sun Jul 25 00:45:22    shutdown: waiting for fs preallocator...
[interruptThread] Sun Jul 25 00:45:22    shutdown: closing all files...
Sun Jul 25 00:45:22      closeAllFiles() finished
[interruptThread] Sun Jul 25 00:45:22    shutdown: removing fs lock...
Sun Jul 25 00:45:22  dbexit: really exiting now</pre>
<p><strong>4.  configuration file</strong></p>
<p>如果嫌命令行参数太长，可以考虑使用配置文件。</p>
<pre>$ cat test.conf
dbpath = /var/mongodb
logpath = /var/test.log
logappend = true
fork = true
port = 1234

$ sudo ./mongod --config test.conf
forked process: 2262
all output going to: /var/test.log</pre>
<p><strong>5. db.serverStatus</strong></p>
<p>在  mongo 中执行 admin.serverStatus() 命令可以获取 MongoDB 的运行统计信息。</p>
<pre>$ ./mongo

MongoDB shell version: 1.5.4
connecting to: test

&gt; use admin
switched to db admin

&gt; db.serverStatus()
{
        "version" : "1.5.4",
        "uptime" : 23,
        "uptimeEstimate" : 0,
        "localTime" : "Sun Jul 25 2010 01:07:18 GMT+0800 (CST)",
        "globalLock" : {
                "totalTime" : 23074558,
                "lockTime" : 470,
                "ratio" : 0.000020368754192387997
        },
        "mem" : {
                "bits" : 64,
                "resident" : 2,
                "virtual" : 75,
                "supported" : true,
                "mapped" : 0
        },
        "connections" : {
                "current" : 1,
                "available" : 19999
        },
        "extra_info" : {
                "note" : "fields vary by platform",
                "heap_usage_bytes" : 162672,
                "page_faults" : 0
        },
        "indexCounters" : {
                "btree" : {
                        "accesses" : 0,
                        "hits" : 0,
                        "misses" : 0,
                        "resets" : 0,
                        "missRatio" : 0
                }
        },
        "backgroundFlushing" : {
                "flushes" : 0,
                "total_ms" : 0,
                "average_ms" : 0,
                "last_ms" : 0,
                "last_finished" : "Thu Jan 01 1970 08:00:00 GMT+0800 (CST)"
        },
        "opcounters" : {
                "insert" : 0,
                "query" : 1,
                "update" : 0,
                "delete" : 0,
                "getmore" : 0,
                "command" : 2
        },
        "asserts" : {
                "regular" : 0,
                "warning" : 0,
                "msg" : 0,
                "user" : 0,
                "rollovers" : 0
        },
        "ok" : true
}</pre>
<p>相关字段说明：</p>
<ul>
<li> uptime: 服务器运行时间(秒)。</li>
<li> localTime: 服务器本地时间。</li>
<li> mem: 服务器内存信息。</li>
<li> connections: 当前连接数。</li>
<li> opcounters: 操作统计。</li>
</ul>
<p><strong>6. db.stats</strong></p>
<p>db.stats  查看数据库状态信息。</p>
<pre>&gt; db.stats()
{
        "collections" : 5,
        "objects" : 18,
        "avgObjSize" : 50.888888888888886,
        "dataSize" : 916,
        "storageSize" : 26112,
        "numExtents" : 5,
        "indexes" : 5,
        "indexSize" : 40960,
        "fileSize" : 201326592,
        "ok" : 1
}</pre>
<p><strong>7. http console</strong></p>
<p>Mongod 默认会打开一个 HTTP  监听端口，通过浏览器我们能获取 MongoDB 服务器的相关状态信息。如果不想启动 HTTP Listening，可以使用  &#8211;nohttpinterface 参数。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --nohttpinterface

Sun Jul 25 01:46:53 MongoDB starting : pid=2406 port=27017 dbpath=/var/mongodb 64-bit

** NOTE: This is a development version (1.5.4) of MongoDB.
**       Not recommended for production.

Sun Jul 25 01:46:53 db version v1.5.4, pdfile version 4.5
Sun Jul 25 01:46:53 git version: 6c1361df41d9cabf9026364427a7df44b3c304fd
Sun Jul 25 01:46:53 sys info: Linux domU-12-31-39-06-79-A1 2.6.21.7-2.ec2.v1.2.fc8xen #1 ...
[initandlisten] Sun Jul 25 01:46:53 waiting for connections on port 27017

^C

Sun Jul 25 01:47:19 got kill or ctrl c signal 2 (Interrupt), will terminate after current cmd ends
[interruptThread] Sun Jul 25 01:47:19 now exiting
Sun Jul 25 01:47:19  dbexit:
[interruptThread] Sun Jul 25 01:47:19    shutdown: going to close listening sockets...
[interruptThread] Sun Jul 25 01:47:19    going to close listening socket: 5
[interruptThread] Sun Jul 25 01:47:19    going to close listening socket: 6
[interruptThread] Sun Jul 25 01:47:19    shutdown: going to flush oplog...
[interruptThread] Sun Jul 25 01:47:19    shutdown: going to close sockets...
[interruptThread] Sun Jul 25 01:47:19    shutdown: waiting for fs preallocator...
[interruptThread] Sun Jul 25 01:47:19    shutdown: closing all files...
Sun Jul 25 01:47:19      closeAllFiles() finished
[interruptThread] Sun Jul 25 01:47:19    shutdown: removing fs lock...
Sun Jul 25 01:47:19  dbexit: really exiting now</pre>
<p>除了用浏览器查看状态信息外，还 可以使用 &#8211;rest 参数打开 RESTful 操作。</p>
<pre>$ sudo ./mongod --dbpath /var/mongodb --rest --fork --logpath /dev/null
forked process: 2451
all output going to: /dev/null

$ curl <a title="http://localhost:28017/serverStatus?text" href="http://localhost:28017/serverStatus?text" target="_blank">http://localhost:28017/serverStatus?text</a>
{ "version" : "1.5.4",
  "uptime" : 13,
  "uptimeEstimate" : 0,
  "localTime" : Date( "Thu May 24 14:12:39 4253" ),
  "globalLock" : { "totalTime" : 13207178,
    "lockTime" : 400,
    "ratio" : 3.028656083835623e-05 },
  "mem" : { "bits" : 64,
    "resident" : 2,
    "virtual" : 67,
    "supported" : true,
    "mapped" : 0 },
  "connections" : { "current" : 0,
    "available" : 20000 },
  "extra_info" : { "note" : "fields vary by platform",
    "heap_usage_bytes" : 158000,
    "page_faults" : 0 },
  "indexCounters" : { "btree" : { "accesses" : 0,
      "hits" : 0,
      "misses" : 0,
      "resets" : 0,
      "missRatio" : 0 } },
  "backgroundFlushing" : { "flushes" : 0,
    "total_ms" : 0,
    "average_ms" : 0,
    "last_ms" : 0,
    "last_finished" : Date( 0 ) },
  "opcounters" : { "insert" : 0,
    "query" : 1,
    "update" : 0,
    "delete" : 0,
    "getmore" : 0,
    "command" : 0 },
  "asserts" : { "regular" : 0,
    "warning" : 0,
    "msg" : 0,
    "user" : 0,
    "rollovers" : 0 } }

$ curl <a title="http://localhost:28017/blog/users/" href="http://localhost:28017/blog/users/" target="_blank">http://localhost:28017/blog/users/</a>
{
  "offset" : 0,
  "rows": [
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e53" }, "name" : "user0" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e54" }, "name" : "user1" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e55" }, "name" : "user2" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e56" }, "name" : "user3" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e57" }, "name" : "user4" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e58" }, "name" : "user5" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e59" }, "name" : "user6" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e5a" }, "name" : "user7" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e5b" }, "name" : "user8" } ,
    { "_id" : { "$oid" : "4c4b2998a09020a0e7681e5c" }, "name" : "user9" }
  ],

  "total_rows" : 10 ,
  "query" : {} ,
  "millis" : 0
}</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5301/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5301/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5301/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5301/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5301/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5301/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 4. Index</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5300/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5300/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:05:41 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5300</guid>
		<description><![CDATA[MongoDB 提供了多样性的索引支持。 &#62; for (var i = 0; i &#60; 30; i++) { ... u = { name : "user" + i, ... age : 20 + i, ... contact : { ... address : ["address1_" + i, "address2_" + i], ... postcode : 100000 + i, ... } ... }; ... db.users.insert(u); ... } [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 提供了多样性的索引支持。</p>
<pre>&gt; for (var i = 0; i &lt; 30; i++) {
...     u = { name : "user" + i,
...           age : 20 + i,
...           contact : {
...              address : ["address1_" + i, "address2_" + i],
...              postcode : 100000 + i,
...           }
...     };
...     db.users.insert(u);
... }</pre>
<p>索引信息被保存在 system.indexes 中，且默认总是为 _id 创建索引。<br />
<span id="more-5300"></span></p>
<pre>&gt; show collections
system.indexes
users

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }</pre>
<p><strong>1.  ensureIndex / dropIndex / reIndex</strong></p>
<p>使用 ensureIndex  创建索引，dropIndex() 删除索引，dropIndexes() 删除全部索引(不包括 _id 等系统索引)。</p>
<pre>&gt; db.users.ensureIndex({name:1})
&gt; db.users.ensureIndex({age:1})

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("4c4a...b798"), "ns" : "blog.users", "key" : { "name" : 1 }, "name" : "name_1" }
{ "_id" : ObjectId("4c4a...b799"), "ns" : "blog.users", "key" : { "age" : 1 }, "name" : "age_1" }

&gt; db.users.dropIndex({age:1})
{ "nIndexesWas" : 3, "ok" : true }

&gt; db.users.dropIndexes()
{
        "nIndexesWas" : 2,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : true
}

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }</pre>
<p>reIndex  则是重建索引。</p>
<pre>&gt; db.users.ensureIndex({name:1})
&gt; db.users.ensureIndex({age:1})

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("4c4a...b82a"), "ns" : "blog.users", "key" : { "name" : 1 }, "name" : "name_1" }
{ "_id" : ObjectId("4c4a...b82b"), "ns" : "blog.users", "key" : { "age" : 1 }, "name" : "age_1" }

&gt; db.users.reIndex()
{
        "nIndexesWas" : 3,
        "msg" : "indexes dropped for collection",
        "ok" : 1,
        "nIndexes" : 3,
        "indexes" : [
                {
                        "name" : "_id_",
                        "ns" : "blog.users",
                        "key" : {
                                "_id" : 1
                        }
                },
                {
                        "_id" : ObjectId("4c4a...b82a"),
                        "ns" : "blog.users",
                        "key" : {
                                "name" : 1
                        },
                        "name" : "name_1"
                },
                {
                        "_id" : ObjectId("4c4a...b82b"),
                        "ns" : "blog.users",
                        "key" : {
                                "age" : 1
                        },
                        "name" : "age_1"
                }
        ],
        "ok" : 1
}</pre>
<p>当系统已有大量数据时，创建索引就是个非常耗时的活，我们可以在后台执行。</p>
<pre>&gt; db.users.dropIndexes()
{
        "nIndexesWas" : 3,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : true
}

&gt; db.users.ensureIndex({name:1}, {backgroud:true})

&gt; db.users.reIndex({backgroud:true})
{
        "nIndexesWas" : 2,
        "msg" : "indexes dropped for collection",
        "ok" : 1,
        "nIndexes" : 2,
        "indexes" : [
                {
                        "name" : "_id_",
                        "ns" : "blog.users",
                        "key" : {
                                "_id" : 1
                        }
                },
                {
                        "_id" : ObjectId("4c4a...b79c"),
                        "ns" : "blog.users",
                        "key" : {
                                "name" : 1
                        },
                        "name" : "name_1",
                        "backgroud" : true
                }
        ],
        "ok" : 1
}</pre>
<p><strong>2. explain</strong></p>
<p>MongoDB 提供了一个 explain  命令让我们获知系统如何处理查询请求。</p>
<pre>&gt; db.users.ensureIndex({name:1})
&gt; db.users.ensureIndex({age:1})

&gt; db.users.find({age:{$gt:45}}, {name:1, age:1})
{ "_id" : ObjectId("4c4a8edeeb257107735eb826"), "name" : "user26", "age" : 46 }
{ "_id" : ObjectId("4c4a8edeeb257107735eb827"), "name" : "user27", "age" : 47 }
{ "_id" : ObjectId("4c4a8edeeb257107735eb828"), "name" : "user28", "age" : 48 }
{ "_id" : ObjectId("4c4a8edeeb257107735eb829"), "name" : "user29", "age" : 49 }

&gt; db.users.find({age:{$gt:45}}, {name:1, age:1}).explain()
{
        "cursor" : "BtreeCursor age_1",
        "nscanned" : 5,
        "nscannedObjects" : 4,
        "n" : 4,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "age" : 45
                        },
                        {
                                "age" : 1.7976931348623157e+308
                        }
                ]
        ]
}</pre>
<p>返回结果信息包括:</p>
<ul>
<li> cursor: 返回游标类型(BasicCursor  或 BtreeCursor)。</li>
<li> nscanned: 被扫描的文档数量。</li>
<li> n: 返回的文档数量。</li>
<li> millis: 耗时(毫秒)。</li>
<li> indexBounds: 所使用的索引。</li>
</ul>
<p>利用 explain  命令，我们可以很好地观察系统如何使用索引来加快检索，同时可以针对性优化索引。</p>
<p><strong>3. Embedded Keys Index</strong></p>
<p>我 们可以创建深层索引，甚至直接用文档(sub-document)作为索引键。</p>
<pre>&gt; db.users.ensureIndex({"contact.postcode":1})

&gt; db.users.find({"contact.postcode":{$lt:100009}}, {name:1, "contact.postcode":1})
{ "_id" : ObjectId("4c4a8edeeb257107735eb80c"), "name" : "user0", "contact" : { "postcode" : 100000 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb80d"), "name" : "user1", "contact" : { "postcode" : 100001 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb80e"), "name" : "user2", "contact" : { "postcode" : 100002 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb80f"), "name" : "user3", "contact" : { "postcode" : 100003 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb810"), "name" : "user4", "contact" : { "postcode" : 100004 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb811"), "name" : "user5", "contact" : { "postcode" : 100005 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb812"), "name" : "user6", "contact" : { "postcode" : 100006 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb813"), "name" : "user7", "contact" : { "postcode" : 100007 } }
{ "_id" : ObjectId("4c4a8edeeb257107735eb814"), "name" : "user8", "contact" : { "postcode" : 100008 } }

&gt; db.users.find({"contact.postcode":{$lt:100009}}, {name:1, "contact.postcode":1}).explain()
{
        "cursor" : "BtreeCursor contact.postcode_1",
        "nscanned" : 10,
        "nscannedObjects" : 9,
        "n" : 9,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "contact.postcode" : -1.7976931348623157e+308
                        },
                        {
                                "contact.postcode" : 100009
                        }
                ]
        ]
}</pre>
<p>我们直接用 contact 创建索引，查找其下属性时可使用该索引，但需注意语法。</p>
<p>(附注: 在 1.5.4  mongo 中，一直无法使用 contact:{postcode:xxx} 这样的 SubObject 语法查询数据，只能用  &#8220;contact.postcode&#8221; DotNotation 语法)</p>
<pre>&gt; db.users.dropIndex({"contact.postcode":1})
{ "nIndexesWas" : 4, "ok" : true }

&gt; db.users.ensureIndex({contact:1})

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("4c4a...b82a"), "ns" : "blog.users", "key" : { "name" : 1 }, "name" : "name_1" }
{ "_id" : ObjectId("4c4a...b82b"), "ns" : "blog.users", "key" : { "age" : 1 }, "name" : "age_1" }
{ "_id" : ObjectId("4c4a...b82d"), "ns" : "blog.users", "key" : { "contact" : 1 }, "name" : "contact_1" }

&gt; db.users.find({contact:{postcode:{$lt:100009}}}).explain()
{
        "cursor" : "BtreeCursor contact_1",
        "nscanned" : 0,
        "nscannedObjects" : 0,
        "n" : 0,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "contact" : {
                                        "postcode" : {
                                                "$lt" : 100009
                                        }
                                }
                        },
                        {
                                "contact" : {
                                        "postcode" : {
                                                "$lt" : 100009
                                        }
                                }
                        }
                ]
        ]
}

&gt; db.users.find({"contact.postcode":{$lt:100009}}).explain() // 无法使用索引
{
        "cursor" : "BasicCursor",
        "nscanned" : 30,
        "nscannedObjects" : 30,
        "n" : 9,
        "millis" : 0,
        "indexBounds" : [ ]
}

&gt; db.users.find({contact:{address:"address2_23"}}).explain()
{
        "cursor" : "BtreeCursor contact_1",
        "nscanned" : 0,
        "nscannedObjects" : 0,
        "n" : 0,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "contact" : {
                                        "address" : "address2_23"
                                }
                        },
                        {
                                "contact" : {
                                        "address" : "address2_23"
                                }
                        }
                ]
        ]
}

&gt; db.users.find({"contact.address":"address2_23"}).explain() // 无法使用索引
{
        "cursor" : "BasicCursor",
        "nscanned" : 30,
        "nscannedObjects" : 30,
        "n" : 1,
        "millis" : 0,
        "indexBounds" : [ ]
}</pre>
<p>同样的语法问题在 Python 中一样生效。</p>
<pre>&gt;&gt;&gt; db.users.find({"contact":{"postcode":{"$lt":100009}}}).explain()
{u'allPlans': [{u'cursor': u'BtreeCursor contact_1',
                u'indexBounds': [[{u'contact': {u'postcode': {u'$lt': 100009}}},
                                  {u'contact': {u'postcode': {u'$lt': 100009}}}]]}],
 u'cursor': u'BtreeCursor contact_1',
 u'indexBounds': [[{u'contact': {u'postcode': {u'$lt': 100009}}},
                   {u'contact': {u'postcode': {u'$lt': 100009}}}]],
 u'millis': 0,
 u'n': 0,
 u'nscanned': 0,
 u'nscannedObjects': 0,
 u'oldPlan': {u'cursor': u'BtreeCursor contact_1',
              u'indexBounds': [[{u'contact': {u'postcode': {u'$lt': 100009}}},
                                {u'contact': {u'postcode': {u'$lt': 100009}}}]]}}

&gt;&gt;&gt; db.users.find({"contact.postcode":{"$lt":100009}}).explain()
{u'allPlans': [{u'cursor': u'BasicCursor', u'indexBounds': []}],
 u'cursor': u'BasicCursor',
 u'indexBounds': [],
 u'millis': 0,
 u'n': 8,
 u'nscanned': 30,
 u'nscannedObjects': 30,
 u'oldPlan': {u'cursor': u'BasicCursor', u'indexBounds': []}}</pre>
<p><strong>4.  Compound Keys Index</strong></p>
<p>创建复合索引也很简单 (1: ascending; -1:  descending)。</p>
<pre>&gt; db.users.ensureIndex({name:1, age:-1})

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ..., "ns" : "blog.users", "key" : { "name" : 1 }, "name" : "name_1" }
{ "_id" : ..., "ns" : "blog.users", "key" : { "age" : 1 }, "name" : "age_1" }
{ "_id" : ..., "ns" : "blog.users", "key" : { "contact" : 1 }, "name" : "contact_1" }
{ "_id" : ..., "ns" : "blog.users", "key" : { "name" : 1, "age" : -1 }, "name" : "name_1_age_-1" }

&gt; db.users.find({age:{$lt:25}, name:"user2"}, {name:1, age:1})
{ "_id" : ObjectId("4c4a8edeeb257107735eb80e"), "name" : "user2", "age" : 22 }

&gt; db.users.find({age:{$lt:25}, name:"user2"}, {name:1, age:1}).explain()
{
        "cursor" : "BtreeCursor name_1_age_-1",
        "nscanned" : 1,
        "nscannedObjects" : 1,
        "n" : 1,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "name" : "user2",
                                "age" : 25
                        },
                        {
                                "name" : "user2",
                                "age" : -1.7976931348623157e+308
                        }
                ]
        ]
}</pre>
<p>复合索引同样可用于局部属性的搜索，但必须依照索引字段顺序。比如创建索引字段顺序 &#8220;a,b,c&#8221;，那么仅对  &#8220;a,b,c&#8221;、&#8221;a,b&#8221;、&#8221;a&#8221; 查询有效，而对 &#8220;b,c&#8221; 之类的组合无效。</p>
<pre>&gt; db.users.dropIndex({name:1})
{ "nIndexesWas" : 5, "ok" : true }

&gt; db.users.dropIndex({age:1})
{ "nIndexesWas" : 4, "ok" : true }

&gt; db.users.dropIndex({contact:1})
{ "nIndexesWas" : 3, "ok" : true }

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("4c4a9...b82e"), "ns" : "blog.users", "key" : { "name" : 1, "age" : -1 }, "name" : "name_1_age_-1" }

&gt; db.users.find({name:"user12"}).explain() // 索引有效
{
        "cursor" : "BtreeCursor name_1_age_-1",
        "nscanned" : 1,
        "nscannedObjects" : 1,
        "n" : 1,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "name" : "user12",
                                "age" : {
                                        "$maxElement" : 1
                                }
                        },
                        {
                                "name" : "user12",
                                "age" : {
                                        "$minElement" : 1
                                }
                        }
                ]
        ]
}

&gt; db.users.find({age:18}).explain() // 索引无效
{
        "cursor" : "BasicCursor",
        "nscanned" : 30,
        "nscannedObjects" : 30,
        "n" : 0,
        "millis" : 0,
        "indexBounds" : [ ]
}</pre>
<p><strong>5. Unique Index</strong></p>
<p>只需在 ensureIndex 命令中指定 unique  即可创建唯一索引。</p>
<pre>&gt; db.users.ensureIndex({name:1}, {unique:true})

&gt; db.system.indexes.find()
{ "name" : "_id_", "ns" : "blog.users", "key" : { "_id" : 1 } }
{ "_id" : ..., "ns" : "blog.users", "key" : { "name" : 1, "age" : -1 }, "name" : "name_1_age_-1" }
{ "_id" : ..., "ns" : "blog.users", "key" : { "name" : 1 }, "name" : "name_1", "unique" : true }

&gt; db.users.insert({name:"user1"})
E11000 duplicate key error index: blog.users.$name_1  dup key: { : "user1" }</pre>
<p>如 果创建唯一索引前已经有重复文档，那么可以用 dropDups 删除多余的数据。</p>
<pre>&gt; db.users.dropIndexes()
{
        "nIndexesWas" : 3,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : true
}

&gt; db.users.insert({name:"user1"})

&gt; db.users.find({name:"user1"}, {name:1})
{ "_id" : ObjectId("4c4a9573eb257107735eb831"), "name" : "user1" }
{ "_id" : ObjectId("4c4a8edeeb257107735eb80d"), "name" : "user1" }

&gt; db.users.ensureIndex({name:1}, {unique:true, dropDups:true})
E11000 duplicate key error index: blog.users.$name_1  dup key: { : "user1" }

&gt; db.users.find({name:"user1"}, {name:1})
{ "_id" : ObjectId("4c4a9573eb257107735eb831"), "name" : "user1" }</pre>
<p><strong>6.  Multikeys</strong></p>
<p>对于数组类型属性，会自动索引全部数组元素。</p>
<pre>&gt; db.users.dropIndexes()
{
        "nIndexesWas" : 1,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : true
}

&gt; db.users.ensureIndex({"contact.address":1})

&gt; db.users.find({"contact.address":"address2_13"}).explain()
{
        "cursor" : "BtreeCursor contact.address_1",
        "nscanned" : 1,
        "nscannedObjects" : 1,
        "n" : 1,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "contact.address" : "address2_13"
                        },
                        {
                                "contact.address" : "address2_13"
                        }
                ]
        ]
}</pre>
<p><strong>7. hint</strong></p>
<p>hint 命令可以强制使用某个索引。</p>
<pre>&gt; db.users.dropIndexes()
{
        "nIndexesWas" : 2,
        "msg" : "non-_id indexes dropped for collection",
        "ok" : true
}

&gt; db.users.ensureIndex({name:1, age:1})

&gt; db.users.find({age:{$lt:30}}).explain()
{
        "cursor" : "BasicCursor",
        "nscanned" : 30,
        "nscannedObjects" : 30,
        "n" : 9,
        "millis" : 0,
        "indexBounds" : [ ]
}

&gt; db.users.find({age:{$lt:30}}).hint({name:1, age:1}).explain()
{
        "cursor" : "BtreeCursor name_1_age_1",
        "nscanned" : 30,
        "nscannedObjects" : 9,
        "n" : 9,
        "millis" : 0,
        "indexBounds" : [
                [
                        {
                                "name" : {
                                        "$minElement" : 1
                                },
                                "age" : -1.7976931348623157e+308
                        },
                        {
                                "name" : {
                                        "$maxElement" : 1
                                },
                                "age" : 30
                        }
                ]
        ]
}</pre>
<p>注意 Python 代码中写法。</p>
<pre>&gt;&gt;&gt; db.users.find({"age":{"$lt":30}}).hint([("name", ASCENDING), ("age", ASCENDING)]).explain()
{u'cursor': u'BtreeCursor name_1_age_1',
 u'indexBounds': [[{u'age': -1.7976931348623157e+308,
                    u'name': {u'$minElement': 1}},
                   {u'age': 30, u'name': {u'$maxElement': 1}}]],
 u'millis': 0,
 u'n': 9,
 u'nscanned': 30,
 u'nscannedObjects': 9}</pre>
<p><strong>8. totalIndexSize</strong></p>
<p>MongoDB  会将索引数据载入内存，以提高查询速度。我们可以用 totalIndexSize 获取全部索引数据大小。</p>
<pre>&gt; db.users.totalIndexSize()
16384</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5300/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5300/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5300/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5300/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5300/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5300/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 3. Schema Design</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5297/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5297/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:03:53 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5297</guid>
		<description><![CDATA[1. Document-Oriented MongoDB 是一种面向文档(document-oriented)的数据库，其内存储的是一种 JSON-like 结构化数据。尽管拥有和关系型数据库 Database/Table 类似的的 DB/Collection 概念，但同一 Collection 内的 Document 可以拥有不同的属性。 (注: 以下 &#62; 提示符表示 mongo JS 代码，&#62;&#62;&#62; 为 Python 代码) &#62; use blog switched to db blog &#62; db.users.insert({name:"user1", age:15}) &#62; db.users.insert({name:"user2", age:20, sex:1}) &#62; db.users.find() { "_id" : ObjectId("4c479885089df9b53474170a"), "name" : "user1", "age" : 15 } { "_id" : ObjectId("4c479896089df9b53474170b"), [...]]]></description>
			<content:encoded><![CDATA[<p><strong>1. Document-Oriented</strong></p>
<p><a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a>  是一种面向文档(document-oriented)的数据库，其内存储的是一种 JSON-like 结构化数据。尽管拥有和关系型数据库  <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">Database</a>/Table 类似的的 DB/Collection 概念，但同一 Collection 内的 Document  可以拥有不同的属性。</p>
<p>(注: 以下 &gt; 提示符表示 mongo JS 代码，&gt;&gt;&gt; 为 Python  代码)</p>
<pre>&gt; use blog
switched to db blog

&gt; db.users.insert({name:"user1", age:15})
&gt; db.users.insert({name:"user2", age:20, sex:1})

&gt; db.users.find()
{ "_id" : ObjectId("4c479885089df9b53474170a"), "name" : "user1", "age" : 15 }
{ "_id" : ObjectId("4c479896089df9b53474170b"), "name" : "user2", "age" : 20, "sex" : 1 }</pre>
<p><span id="more-5297"></span><br />
可以通过 $exists 判断某个字段是否存在。</p>
<pre>&gt; db.users.find({sex:{$exists:true}})
{ "_id" : ObjectId("4c479896089df9b53474170b"), "name" : "user2", "age" : 20, "sex" : 1 }</pre>
<p><strong>2.  Embed vs. Reference</strong></p>
<p>Document 采取 JSON-like  这种层级结构，因此我们可以直接用嵌入(Embed)代替传统关系型数据库的关联引用(Reference)。</p>
<pre>&gt; u = db.users.findOne({name:"user1"})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15
}

&gt; u.address = ["address1", "address2"]
[ "address1", "address2" ]

&gt; db.users.save(u)

&gt; db.users.findOne({name:"user1"})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15,
        "address" : [
                "address1",
                "address2"
        ]
}

&gt; db.users.findOne({address:"address1"})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15,
        "address" : [
                "address1",
                "address2"
        ]
}</pre>
<p>MongoDB 支持以 &#8220;.&#8221; 分割的 namespace 路径，但需要注意 key 不能以 &#8220;$&#8221; 开头，不能包含  &#8220;.&#8221; 字符 (条件表达式中的多级路径须用引号)。</p>
<pre>&gt; u = db.users.findOne({address:"address1"})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15,
        "address" : [
                "address1",
                "address2"
        ]
}

&gt; u.im = {msn:"user1@hotmail.com", qq:12345678}
{ "msn" : "user1@hotmail.com", "qq" : 12345678 }

&gt; db.users.save(u)

&gt; u = db.users.findOne({"im.qq":12345678})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15,
        "address" : [
                "address1",
                "address2"
        ],
        "im" : {
                "msn" : "user1@hotmail.com",
                "qq" : 12345678
        }
}

&gt; u.im.qq
12345678

&gt; u.im.msn
user1@hotmail.com

&gt; db.users.update({"im.qq":12345678}, {$set:{"im.qq":12345}})

&gt; u = db.users.findOne({"im.qq":12345})
{
        "_id" : ObjectId("4c479885089df9b53474170a"),
        "name" : "user1",
        "age" : 15,
        "address" : [
                "address1",
                "address2"
        ],
        "im" : {
                "msn" : "user1@hotmail.com",
                "qq" : 12345
        }
}

&gt; u = db.users.find({"im.qq":{$exists:true}}, {"im.qq":1})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "im" : { "qq" : 12345 } }</pre>
<p>注 意: 由于每篇文档都包含完整的 key 数据，因此使用尽可能短的 key 可以有效节省存储空间。</p>
<p><strong>3. Operator</strong></p>
<p>(1)  $all: 判断数组属性是否包含全部条件。</p>
<pre>&gt; db.users.insert({name:"user3", data:[1,2,3,4,5,6,7]})
&gt; db.users.insert({name:"user4", data:[1,2,3]})

&gt; db.users.find({data:{$all:[2,3,4]}})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "name" : "user3", "data" : [ 1, 2, 3, 4, 5, 6, 7 ] }</pre>
<p>注 意和 $in 的区别。$in 是检查目标属性值是条件表达式中的一员，而 $all 则要求属性值包含全部条件元素。</p>
<p>(2)  $size: 匹配数组属性元素数量。</p>
<pre>&gt; db.users.insert({name:"user3", data:[1,2,3,4,5,6,7]})
&gt; db.users.insert({name:"user4", data:[1,2,3]})

&gt; db.users.find({data:{$size:3}})
{ "_id" : ObjectId("4c47a13bb48cde79c6780df1"), "name" : "user4", "data" : [ 1, 2, 3 ] }</pre>
<p>(3)  $type: 判断属性类型。</p>
<pre>&gt; db.users.insert({name:"user5", t:1})
&gt; db.users.insert({name:"user6", t:1.34})
&gt; db.users.insert({name:"user7", t:"abc"})

&gt; db.users.find({t:{$type:1}})
{ "_id" : ObjectId("4c47a231b48cde79c6780df2"), "name" : "user5", "t" : 1 }
{ "_id" : ObjectId("4c47a23eb48cde79c6780df3"), "name" : "user6", "t" : 1.34 }

&gt; db.users.find({t:{$type:2}})
{ "_id" : ObjectId("4c47a258b48cde79c6780df4"), "name" : "user7", "t" : "abc" }</pre>
<p>类 型值:</p>
<ul>
<li> double:1</li>
<li> string: 2</li>
<li> object: 3</li>
<li> array: 4</li>
<li> binary data: 5</li>
<li> object id: 7</li>
<li> boolean: 8</li>
<li> date: 9</li>
<li> null: 10</li>
<li> regular  expression: 11</li>
<li> javascript code: 13</li>
<li> symbol: 14</li>
<li> javascript code with scope: 15</li>
<li> 32-bit integer: 16</li>
<li> timestamp: 17</li>
<li> 64-bit integer: 18</li>
<li> min key: 255</li>
<li> max key: 127</li>
</ul>
<p>(4) 使用正则表达式进行查询。</p>
<pre>&gt; db.users.find({name:/user[135]/i}, {name:1})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "name" : "user1" }
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "name" : "user3" }
{ "_id" : ObjectId("4c47a231b48cde79c6780df2"), "name" : "user5" }

&gt;&gt;&gt; users = db.users.find({"name" : {"$regex" : r"(?i)user[135]"}}, ["name"])
&gt;&gt;&gt; for u in users: print u
...
{u'_id': ObjectId('4c479885089df9b53474170a'), u'name': u'user1'}
{u'_id': ObjectId('4c47a133b48cde79c6780df0'), u'name': u'user3'}
{u'_id': ObjectId('4c47a231b48cde79c6780df2'), u'name': u'user5'}</pre>
<p>正 则表达式标记:</p>
<p>i: 忽略大小写。<br />
m: 默认为单行处理，此标记表示多行。<br />
x: 扩展。</p>
<p>(5)  数组属性元素值匹配。</p>
<pre>&gt; db.users.find({data:"abc"})
{ "_id" : ObjectId("4c47a481b48cde79c6780df5"), "name" : "user8", "data" : [ { "a" : 1, "b" : 10 }, 3, "abc" ] }

&gt; db.users.find({data:{$elemMatch:{a:1, b:{$gt:5}}}})
{ "_id" : ObjectId("4c47a481b48cde79c6780df5"), "name" : "user8", "data" : [ { "a" : 1, "b" : 10 }, 3, "abc" ] }</pre>
<p>{data:&#8221;abc&#8221;}  仅简单匹配数组属性是否包含该元素。$elemMatch 则可以处理更复杂的元素查找条件。当然也可以写成如下方式。</p>
<pre>&gt; db.users.find({"data.a":1, "data.b":{$gt:5}})
{ "_id" : ObjectId("4c47a481b48cde79c6780df5"), "name" : "user8", "data" : [ { "a" : 1, "b" : 10 }, 3, "abc" ] }</pre>
<p>还 可以直接使用序号进行操作。</p>
<pre>&gt; db.users.find({"data.2":3})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "name" : "user3", "data" : [ 1, 2, 3, 4, 5, 6, 7 ] }
{ "_id" : ObjectId("4c47a13bb48cde79c6780df1"), "name" : "user4", "data" : [ 1, 2, 3 ] }</pre>
<p>(6)  $not: 取反，表示返回条件不成立的文档。</p>
<p>似乎只能跟正则和 $mod 一起使用？？？？</p>
<pre>&gt; u = db.users.find({name:{$not:/user3/}}, {name:1})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "name" : "user1" }
{ "_id" : ObjectId("4c47a13bb48cde79c6780df1"), "name" : "user4" }
{ "_id" : ObjectId("4c47a231b48cde79c6780df2"), "name" : "user5" }
{ "_id" : ObjectId("4c47a23eb48cde79c6780df3"), "name" : "user6" }
{ "_id" : ObjectId("4c47a258b48cde79c6780df4"), "name" : "user7" }
{ "_id" : ObjectId("4c47a481b48cde79c6780df5"), "name" : "user8" }
{ "_id" : ObjectId("4c479896089df9b53474170b"), "name" : "user2" }</pre>
<p>(7)  $unset: 和 $set 相反，表示移除文档属性。</p>
<pre>&gt; u = db.users.find({name:"user1"})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "name" : "user1", "age" : 15, "address" : [ "address1", "address2" ], "im" : { "msn" : "user1@hotmail.com", "qq" : 12345 } }

&gt; db.users.update({name:"user1"}, {$unset:{address:1, im:1}})

&gt; u = db.users.find({name:"user1"})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "age" : 15, "name" : "user1" }</pre>
<p>(8)  $push: 和 $ pushAll 都是向数组属性添加元素。</p>
<pre>&gt; u = db.users.find({name:"user1"})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "age" : 15, "name" : "user1" }

&gt; db.users.update({name:"user1"}, {$push:{data:1}})

&gt; u = db.users.find({name:"user1"})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "age" : 15, "data" : [ 1 ], "name" : "user1" }

&gt; db.users.update({name:"user1"}, {$pushAll:{data:[2,3,4,5]}})

&gt; u = db.users.find({name:"user1"})
{ "_id" : ObjectId("4c479885089df9b53474170a"), "age" : 15, "data" : [ 1, 2, 3, 4, 5 ], "name" : "user1" }</pre>
<p>(9)  $addToSet: 和 $push 类似，不过仅在该元素不存在时才添加 (Set 表示不重复元素集合)。</p>
<pre>&gt; db.users.update({name:"user2"}, {$addToSet:{data:1}})
&gt; db.users.update({name:"user2"}, {$addToSet:{data:1}})

&gt; u = db.users.find({name:"user2"})
{ "_id" : ObjectId("4c479896089df9b53474170b"), "data" : [ 1 ], "name" : "user2" }
&gt; db.users.update({name:"user2"}, {$push:{data:1}})

&gt; u = db.users.find({name:"user2"})
{ "_id" : ObjectId("4c479896089df9b53474170b"), "data" : [ 1, 1 ], "name" : "user2" }</pre>
<p>要 添加多个元素，使用 $each。</p>
<pre>&gt; db.users.update({name:"user2"}, {$addToSet:{data:{$each:[1,2,3,4]}}})

&gt; u = db.users.find({name:"user2"})
{ "_id" : ObjectId("4c479896089df9b53474170b"), "data" : [ 1, 2, 3, 4 ], "name" : "user2" }</pre>
<p>(10)  $pop: 移除数组属性的元素，$pull 按值移除，$pullAll 移除所有符合提交的元素。</p>
<pre>&gt; u = db.users.find({name:"user3"})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "data" : [ 1, 2, 3, 4, 5, 6, 7, 2, 3 ], "name" : "user3" }

&gt; db.users.update({name:"user3"}, {$pop:{data:1}}) // 移除最后一个元素

&gt; u = db.users.find({name:"user3"})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "data" : [ 1, 2, 3, 4, 5, 6, 7, 2 ], "name" : "user3" }

&gt; db.users.update({name:"user3"}, {$pop:{data:-1}}) // 移除第一个元素

&gt; u = db.users.find({name:"user3"})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "data" : [ 2, 3, 4, 5, 6, 7, 2 ], "name" : "user3" }

&gt; db.users.update({name:"user3"}, {$pull:{data:2}}) // 移除全部 2

&gt; u = db.users.find({name:"user3"})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "data" : [ 3, 4, 5, 6, 7 ], "name" : "user3" }

&gt; db.users.update({name:"user3"}, {$pullAll:{data:[4,5,6]}}) // 移除 4,5,6

&gt; u = db.users.find({name:"user3"})
{ "_id" : ObjectId("4c47a133b48cde79c6780df0"), "data" : [ 3, 7 ], "name" : "user3" }</pre>
<p>(11)  $where: 用 JS 代码来代替有些丑陋的 $lt、$gt。</p>
<p>MongoDB 内置了 Javascript Engine  (SpiderMonkey)。可直接使用 JS Expression，甚至使用 JS Function 写更复杂的 Code Block。</p>
<pre>&gt; for (var i = 0; i &lt; 10; i++) db.users.insert({name:"user"+i, age:i})

&gt; db.users.find()
{ "_id" : ObjectId("4c47b3372a9b2be866da226e"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c47b3372a9b2be866da226f"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2270"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2271"), "name" : "user3", "age" : 3 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2272"), "name" : "user4", "age" : 4 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2273"), "name" : "user5", "age" : 5 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2274"), "name" : "user6", "age" : 6 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2275"), "name" : "user7", "age" : 7 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2276"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2277"), "name" : "user9", "age" : 9 }

&gt; db.users.find({$where:"this.age &gt; 7 || this.age &lt; 3"})
{ "_id" : ObjectId("4c47b3372a9b2be866da226e"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c47b3372a9b2be866da226f"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2270"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2276"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2277"), "name" : "user9", "age" : 9 }

&gt; db.users.find("this.age &gt; 7 || this.age &lt; 3")
{ "_id" : ObjectId("4c47b3372a9b2be866da226e"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c47b3372a9b2be866da226f"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2270"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2276"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2277"), "name" : "user9", "age" : 9 }

&gt; db.users.find({$where: function(){ return this.age &gt; 7 || this.age &lt; 3;}})
{ "_id" : ObjectId("4c47b3372a9b2be866da226e"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c47b3372a9b2be866da226f"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2270"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2276"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c47b3372a9b2be866da2277"), "name" : "user9", "age" : 9 }

&gt;&gt;&gt; for u in db.users.find({"$where":"this.age &gt; 7 || this.age &lt; 3"}): print u
...
{u'age': 0.0, u'_id': ObjectId('4c47b3372a9b2be866da226e'), u'name': u'user0'}
{u'age': 1.0, u'_id': ObjectId('4c47b3372a9b2be866da226f'), u'name': u'user1'}
{u'age': 2.0, u'_id': ObjectId('4c47b3372a9b2be866da2270'), u'name': u'user2'}
{u'age': 8.0, u'_id': ObjectId('4c47b3372a9b2be866da2276'), u'name': u'user8'}
{u'age': 9.0, u'_id': ObjectId('4c47b3372a9b2be866da2277'), u'name': u'user9'}

&gt;&gt;&gt; for u in db.users.find().where("this.age &gt; 7 || this.age &lt; 3"): print u
...
{u'age': 0.0, u'_id': ObjectId('4c47b3372a9b2be866da226e'), u'name': u'user0'}
{u'age': 1.0, u'_id': ObjectId('4c47b3372a9b2be866da226f'), u'name': u'user1'}
{u'age': 2.0, u'_id': ObjectId('4c47b3372a9b2be866da2270'), u'name': u'user2'}
{u'age': 8.0, u'_id': ObjectId('4c47b3372a9b2be866da2276'), u'name': u'user8'}
{u'age': 9.0, u'_id': ObjectId('4c47b3372a9b2be866da2277'), u'name': u'user9'}

&gt;&gt;&gt; for u in db.users.find().where("function() { return this.age &gt; 7 || this.age &lt; 3;}"): print u
...
{u'age': 0.0, u'_id': ObjectId('4c47b3372a9b2be866da226e'), u'name': u'user0'}
{u'age': 1.0, u'_id': ObjectId('4c47b3372a9b2be866da226f'), u'name': u'user1'}
{u'age': 2.0, u'_id': ObjectId('4c47b3372a9b2be866da2270'), u'name': u'user2'}
{u'age': 8.0, u'_id': ObjectId('4c47b3372a9b2be866da2276'), u'name': u'user8'}
{u'age': 9.0, u'_id': ObjectId('4c47b3372a9b2be866da2277'), u'name': u'user9'}</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5297/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5297/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5297/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5297/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5297/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5297/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 2. Basic Usage</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5296/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5296/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:02:56 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5296</guid>
		<description><![CDATA[须安装 PyMongo (Documentation)。 $ sudo easy_install -U pymongo (注: 以下 &#62; 提示符表示 mongo JS 代码，&#62;&#62;&#62; 为 Python 代码) 1. INSERT 使 用 insert 插入文档。 &#62; use blog switched to db blog &#62; u = { name:"user1", age:23 } { "name" : "user1", "age" : 23 } &#62; db.users.insert(u) &#62; u2 = db.users.findOne({name:"user1"}) { "_id" : [...]]]></description>
			<content:encoded><![CDATA[<p>须安装 PyMongo (<a title="http://api.mongodb.org/python/current/index.html" href="http://api.mongodb.org/python/current/index.html" target="_blank">Documentation</a>)。</p>
<pre>$ sudo easy_install -U pymongo</pre>
<p>(注:  以下 &gt; 提示符表示 mongo JS 代码，&gt;&gt;&gt; 为 Python 代码)</p>
<p><strong>1. INSERT</strong></p>
<p>使 用 insert 插入文档。</p>
<pre>&gt; use blog
switched to db blog

&gt; u = { name:"user1", age:23 }
{ "name" : "user1", "age" : 23 }

&gt; db.users.insert(u)

&gt; u2 = db.users.findOne({name:"user1"})
{
        "_id" : ObjectId("4c44fe0edef8f3492fe67d60"),
        "name" : "user1",
        "age" : 23
}

&gt; u2.age += 3
26

&gt; db.users.save(u2)

&gt; db.users.find()
{ "_id" : ObjectId("4c44fe0edef8f3492fe67d60"), "name" : "user1", "age" : 26 }</pre>
<p><span id="more-5296"></span><br />
save()  可插入新文档，也可以更新(update)一个已有的文档。下面是用 PyMongo 写的相同的代码。</p>
<pre>&gt;&gt;&gt; import pymongo
&gt;&gt;&gt; conn = pymongo.Connection(host="192.168.1.202")
&gt;&gt;&gt; db = conn.blog

&gt;&gt;&gt; u = {"name":"user1", "age":23}

&gt;&gt;&gt; db.users.save(u)
ObjectId('4c456e0a499b14047e000000')

&gt;&gt;&gt; u2 = db.users.find_one({"name":"user1"})

&gt;&gt;&gt; u2
{u'age': 23, u'_id': ObjectId('4c456e0a499b14047e000000'), u'name': u'user1'}

&gt;&gt;&gt; u2["age"] += 3

&gt;&gt;&gt; db.users.save(u2)
ObjectId('4c456e0a499b14047e000000')

&gt;&gt;&gt; for u in db.users.find(): print u
...
{u'age': 26, u'_id': ObjectId('4c456e0a499b14047e000000'), u'name': u'user1'}</pre>
<p><strong>2.  Query</strong></p>
<p><a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> 支持多种复杂的查询方式，能实现大多数 T-SQL 功能，远不是 Key-Value 之类的  <a href="http://www.iwanna.cn/tags/nosql/" class="st_tag internal_tag" rel="tag" title="标签 NoSQL 下的日志">NoSQL</a> DB 所能比拟的。<br />
相关函数操作看上去非常像 .NET/C# Linq Method Syntax。<br />
有关查询优化和索引 的细节请参考后文。</p>
<p>先准备好所需的测试数据。</p>
<pre>&gt; use blog
switched to db blog

&gt; for (var i = 0; i &lt; 16; i++) db.users.insert({name:"user" + i, age:20 + i, sex:i % 2})

&gt; db.users.find()
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e8"), "name" : "user9", "age" : 29, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e9"), "name" : "user10", "age" : 30, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ea"), "name" : "user11", "age" : 31, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35, "sex" : 1 }</pre>
<p>主 要用到的查询函数式 find() 和 findOne()，前者返回一个迭代器 cursor，后者返回单个文档。</p>
<p><strong>(1)  WHERE</strong></p>
<p># select * from users where name = &#8216;user1&#8242;</p>
<pre>&gt; db.users.find({name:"user1"})
{ "_id" : ObjectId("4c4528a0b55f2224d447e4b0"), "name" : "user1", "age" : 21, "sex" : 1 }

&gt;&gt;&gt; for u in db.users.find({"name":"user1"}): print u
...
{u'age': 21.0, u'_id': ObjectId('4c4528a0b55f2224d447e4b0'), u'name': u'user1', u'sex': 1.0}</pre>
<p>#  select * from users where name = &#8216;user1&#8242; and age = 21</p>
<pre>&gt; db.users.find({name:"user1", age:21})
{ "_id" : ObjectId("4c4528a0b55f2224d447e4b0"), "name" : "user1", "age" : 21, "sex" : 1 }

&gt;&gt;&gt; for u in db.users.find({"name":"user1", "age":21}): print u
...
{u'age': 21.0, u'_id': ObjectId('4c4528a0b55f2224d447e4b0'), u'name': u'user1', u'sex': 1.0}</pre>
<p><strong>(2)  FIELDS</strong></p>
<p># select name, age from users where age = 21</p>
<pre>&gt; db.users.find({age:21}, {'name':1, 'age':1})
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21 }

&gt;&gt;&gt; for u in db.users.find({"age":21}, ["name", "age"]): print u
...
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1'}</pre>
<p>#  select name, age from users</p>
<pre>&gt; db.users.find({}, {'name':1, 'age':1})
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e8"), "name" : "user9", "age" : 29 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e9"), "name" : "user10", "age" : 30 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ea"), "name" : "user11", "age" : 31 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35 }

&gt;&gt;&gt; for u in db.users.find(fields = ["name", "age"]): print u
...
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0'}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1'}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2'}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3'}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4'}
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5'}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6'}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7'}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8'}
{u'age': 29.0, u'_id': ObjectId('4c452c343d48c8f284b388e8'), u'name': u'user9'}
{u'age': 30.0, u'_id': ObjectId('4c452c343d48c8f284b388e9'), u'name': u'user10'}
{u'age': 31.0, u'_id': ObjectId('4c452c343d48c8f284b388ea'), u'name': u'user11'}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12'}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13'}
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14'}
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15'}</pre>
<p><strong>(3)  SORT</strong></p>
<p># select * from users order by age</p>
<pre>&gt; db.users.find().sort({age:1})
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e8"), "name" : "user9", "age" : 29, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e9"), "name" : "user10", "age" : 30, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ea"), "name" : "user11", "age" : 31, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35, "sex" : 1 }

&gt; db.users.find().sort({age:-1})
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ea"), "name" : "user11", "age" : 31, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e9"), "name" : "user10", "age" : 30, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e8"), "name" : "user9", "age" : 29, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20, "sex" : 0 }

&gt;&gt;&gt; for u in db.users.find().sort([("age", ASCENDING)]): print u
...
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0', u'sex': 0.0}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1', u'sex': 1.0}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6', u'sex': 0.0}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7', u'sex': 1.0}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8', u'sex': 0.0}
{u'age': 29.0, u'_id': ObjectId('4c452c343d48c8f284b388e8'), u'name': u'user9', u'sex': 1.0}
{u'age': 30.0, u'_id': ObjectId('4c452c343d48c8f284b388e9'), u'name': u'user10', u'sex': 0.0}
{u'age': 31.0, u'_id': ObjectId('4c452c343d48c8f284b388ea'), u'name': u'user11', u'sex': 1.0}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12', u'sex': 0.0}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13', u'sex': 1.0}
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14', u'sex': 0.0}
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15', u'sex': 1.0}

&gt;&gt;&gt; for u in db.users.find().sort([("age", DESCENDING)]): print u
...
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15', u'sex': 1.0}
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14', u'sex': 0.0}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13', u'sex': 1.0}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12', u'sex': 0.0}
{u'age': 31.0, u'_id': ObjectId('4c452c343d48c8f284b388ea'), u'name': u'user11', u'sex': 1.0}
{u'age': 30.0, u'_id': ObjectId('4c452c343d48c8f284b388e9'), u'name': u'user10', u'sex': 0.0}
{u'age': 29.0, u'_id': ObjectId('4c452c343d48c8f284b388e8'), u'name': u'user9', u'sex': 1.0}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8', u'sex': 0.0}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7', u'sex': 1.0}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6', u'sex': 0.0}
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1', u'sex': 1.0}
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0', u'sex': 0.0}</pre>
<p>#  select * from users order by sex asce, age desc</p>
<pre>&gt; db.users.find().sort({sex:1, age:-1})
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e9"), "name" : "user10", "age" : 30, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ea"), "name" : "user11", "age" : 31, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e8"), "name" : "user9", "age" : 29, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21, "sex" : 1 }

&gt;&gt;&gt; for u in db.users.find().sort([("sex", ASCENDING), ("age", DESCENDING)]): print u

...
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14', u'sex': 0.0}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12', u'sex': 0.0}
{u'age': 30.0, u'_id': ObjectId('4c452c343d48c8f284b388e9'), u'name': u'user10', u'sex': 0.0}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8', u'sex': 0.0}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6', u'sex': 0.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0', u'sex': 0.0}
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15', u'sex': 1.0}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13', u'sex': 1.0}
{u'age': 31.0, u'_id': ObjectId('4c452c343d48c8f284b388ea'), u'name': u'user11', u'sex': 1.0}
{u'age': 29.0, u'_id': ObjectId('4c452c343d48c8f284b388e8'), u'name': u'user9', u'sex': 1.0}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7', u'sex': 1.0}
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1', u'sex': 1.0}

&gt;&gt;&gt; for u in db.users.find(sort = [("sex", ASCENDING), ("age", DESCENDING)]): print u
...
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14', u'sex': 0.0}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12', u'sex': 0.0}
{u'age': 30.0, u'_id': ObjectId('4c452c343d48c8f284b388e9'), u'name': u'user10', u'sex': 0.0}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8', u'sex': 0.0}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6', u'sex': 0.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0', u'sex': 0.0}
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15', u'sex': 1.0}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13', u'sex': 1.0}
{u'age': 31.0, u'_id': ObjectId('4c452c343d48c8f284b388ea'), u'name': u'user11', u'sex': 1.0}
{u'age': 29.0, u'_id': ObjectId('4c452c343d48c8f284b388e8'), u'name': u'user9', u'sex': 1.0}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7', u'sex': 1.0}
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1', u'sex': 1.0}</pre>
<p><strong>(4)  SLICE</strong></p>
<p># select * from users skip 2 limit 3</p>
<pre>&gt; db.users.find().skip(2).limit(3)
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e3"), "name" : "user4", "age" : 24, "sex" : 0 }

&gt;&gt;&gt; for u in db.users.find().skip(2).limit(3): print u
...
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}

&gt;&gt;&gt; for u in db.users.find(skip = 2, limit = 3): print u
...
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}</pre>
<p>可 以用切片代替 skip &amp; limit (mongo 中的 $slice 貌似有点问题)。</p>
<pre>&gt;&gt;&gt; for u in db.users.find()[2:5]: print u
...
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 24.0, u'_id': ObjectId('4c452c343d48c8f284b388e3'), u'name': u'user4', u'sex': 0.0}</pre>
<p><strong>(5)  Conditional Operators</strong></p>
<p># select * from users where sex = 1  and age &gt; 23 and age &lt; 28</p>
<pre>&gt; db.users.find({sex:1, age:{$gt:23, $lt:28}})
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e6"), "name" : "user7", "age" : 27, "sex" : 1 }

&gt;&gt;&gt; for u in db.users.find({"sex":1, "age":{"$gt":23, "$lt":28}}): print u
...
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 27.0, u'_id': ObjectId('4c452c343d48c8f284b388e6'), u'name': u'user7', u'sex': 1.0}</pre>
<p>比 较操作包括：$gt (&gt;)、$lt (&lt;)、$gte (&gt;=)、$lte(&lt;=)、$ne (!=)。</p>
<p><strong>(6)  IN</strong></p>
<p># select * from users where age in (23, 26, 32)</p>
<pre>&gt; db.users.find({age:{$in:[23,26,32]}})
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e5"), "name" : "user6", "age" : 26, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388eb"), "name" : "user12", "age" : 32, "sex" : 0 }

&gt;&gt;&gt; for u in db.users.find({"age":{"$in":(23, 26, 32)}}): print u
...
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 26.0, u'_id': ObjectId('4c452c343d48c8f284b388e5'), u'name': u'user6', u'sex': 0.0}
{u'age': 32.0, u'_id': ObjectId('4c452c343d48c8f284b388eb'), u'name': u'user12', u'sex': 0.0}</pre>
<p>对 应的操作符有 $nin (not in)。</p>
<p><strong>(7) COUNT</strong></p>
<p># select count(*)  from users where age &gt; 30</p>
<pre>&gt; db.users.find({age:{$gt:30}}).count()
5

&gt;&gt;&gt; db.users.find({"age":{"$gt":30}}).count()
5</pre>
<p><strong>(8) OR</strong></p>
<p># select * from users where age = 25 or  age = 28<br />
# select * from users where age &lt;= 23 or age &gt;= 33</p>
<pre>&gt; db.users.find({$or:[{age:25}, {age:28}]})
{ "_id" : ObjectId("4c452c343d48c8f284b388e4"), "name" : "user5", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e7"), "name" : "user8", "age" : 28, "sex" : 0 }

&gt; db.users.find({$or:[{age:{$lte:23}}, {age:{$gte:33}}]})
{ "_id" : ObjectId("4c452c343d48c8f284b388df"), "name" : "user0", "age" : 20, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e0"), "name" : "user1", "age" : 21, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e1"), "name" : "user2", "age" : 22, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388e2"), "name" : "user3", "age" : 23, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ec"), "name" : "user13", "age" : 33, "sex" : 1 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ed"), "name" : "user14", "age" : 34, "sex" : 0 }
{ "_id" : ObjectId("4c452c343d48c8f284b388ee"), "name" : "user15", "age" : 35, "sex" : 1 }

&gt;&gt;&gt; for u in db.users.find({"$or":[{"age":25}, {"age":28}]}): print u
...
{u'age': 25.0, u'_id': ObjectId('4c452c343d48c8f284b388e4'), u'name': u'user5', u'sex': 1.0}
{u'age': 28.0, u'_id': ObjectId('4c452c343d48c8f284b388e7'), u'name': u'user8', u'sex': 0.0}

&gt;&gt;&gt; for u in db.users.find({"$or":[{"age":{"$lte":23}}, {"age":{"$gte":33}}]}): print u
...
{u'age': 20.0, u'_id': ObjectId('4c452c343d48c8f284b388df'), u'name': u'user0', u'sex': 0.0}
{u'age': 21.0, u'_id': ObjectId('4c452c343d48c8f284b388e0'), u'name': u'user1', u'sex': 1.0}
{u'age': 22.0, u'_id': ObjectId('4c452c343d48c8f284b388e1'), u'name': u'user2', u'sex': 0.0}
{u'age': 23.0, u'_id': ObjectId('4c452c343d48c8f284b388e2'), u'name': u'user3', u'sex': 1.0}
{u'age': 33.0, u'_id': ObjectId('4c452c343d48c8f284b388ec'), u'name': u'user13', u'sex': 1.0}
{u'age': 34.0, u'_id': ObjectId('4c452c343d48c8f284b388ed'), u'name': u'user14', u'sex': 0.0}
{u'age': 35.0, u'_id': ObjectId('4c452c343d48c8f284b388ee'), u'name': u'user15', u'sex': 1.0}</pre>
<p>还 有一些复杂或专用的查询另文记录。</p>
<p><strong>3. Update</strong></p>
<p>可直接用类似 T-SQL 条件表达式更新，或用  Save() 更新从数据库返回到文档对象。</p>
<p># update users set age = 100, sex = 0 where  name = &#8216;user1&#8242;</p>
<pre>&gt; db.users.update({name:"user1"}, {$set:{age:100, sex:0}})

&gt;&gt;&gt; db.users.update({"name":"user1"}, {"$set":{"age":100, "sex":0}})</pre>
<p>update()  有几个参数需要注意。</p>
<pre>db.collection.update(criteria, objNew, upsert, mult)</pre>
<p>criteria:  需要被更新的条件表达式<br />
objNew: 更新表达式<br />
upsert: 如目标记录不存在，是否插入新文档。<br />
multi:  是否更新多个文档。</p>
<p># update users set age = age + 10</p>
<pre>&gt; db.users.update({}, {$inc:{age:10}}, false, true)

&gt;&gt;&gt; db.users.update({}, {"$inc":{"age":10}}, multi=True)</pre>
<p>#  update users set age = age + 10, sex = 1 where name = &#8216;user1&#8242;</p>
<pre>&gt; db.users.update({name:"user1"}, {$inc:{age:10}, $set:{sex:1}})

&gt;&gt;&gt; db.users.update({"name":"user1"}, {"$inc":{"age":10}, "$set":{"sex":1}})</pre>
<p>还 有一些针对集合的更新操作另文记录。</p>
<p><strong>4. Remove</strong></p>
<p>remove()  用于删除单个或全部文档，删除后的文档无法恢复。</p>
<pre>&gt; use blog
switched to db blog

&gt; for (var i = 0; i &lt; 10; i++) db.users.insert({name : "user" + i, age : 20 + i})

&gt; db.users.find()
{ "_id" : ObjectId("4c4508818c4a1e0bf570460d"), "name" : "user0", "age" : 20 }
{ "_id" : ObjectId("4c4508818c4a1e0bf570460e"), "name" : "user1", "age" : 21 }
{ "_id" : ObjectId("4c4508818c4a1e0bf570460f"), "name" : "user2", "age" : 22 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704610"), "name" : "user3", "age" : 23 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704611"), "name" : "user4", "age" : 24 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704612"), "name" : "user5", "age" : 25 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704613"), "name" : "user6", "age" : 26 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704614"), "name" : "user7", "age" : 27 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704615"), "name" : "user8", "age" : 28 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704616"), "name" : "user9", "age" : 29 }

&gt; id = db.users.findOne({name:"user2"})._id
ObjectId("4c4508818c4a1e0bf570460f")

&gt; db.users.remove(id)

&gt; db.users.find()
{ "_id" : ObjectId("4c4508818c4a1e0bf570460d"), "name" : "user0", "age" : 20 }
{ "_id" : ObjectId("4c4508818c4a1e0bf570460e"), "name" : "user1", "age" : 21 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704610"), "name" : "user3", "age" : 23 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704611"), "name" : "user4", "age" : 24 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704612"), "name" : "user5", "age" : 25 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704613"), "name" : "user6", "age" : 26 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704614"), "name" : "user7", "age" : 27 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704615"), "name" : "user8", "age" : 28 }
{ "_id" : ObjectId("4c4508818c4a1e0bf5704616"), "name" : "user9", "age" : 29 }

&gt; db.users.remove()

&gt; db.users.find()</pre>
<p>Python:</p>
<pre>&gt;&gt;&gt; for i in range(10): db.users.insert({"name":"user"+str(i), "age":20+i})
...
ObjectId('4c456e8b499b14047e000001')
ObjectId('4c456e8b499b14047e000002')
ObjectId('4c456e8b499b14047e000003')
ObjectId('4c456e8b499b14047e000004')
ObjectId('4c456e8b499b14047e000005')
ObjectId('4c456e8b499b14047e000006')
ObjectId('4c456e8b499b14047e000007')
ObjectId('4c456e8b499b14047e000008')
ObjectId('4c456e8b499b14047e000009')
ObjectId('4c456e8b499b14047e00000a')

&gt;&gt;&gt; id = db.users.find_one({"name":"user2"})["_id"]

&gt;&gt;&gt; id
ObjectId('4c456e8b499b14047e000003')

&gt;&gt;&gt; db.users.remove(id)

&gt;&gt;&gt; for u in db.users.find(): print u
...
{u'age': 20, u'_id': ObjectId('4c456e8b499b14047e000001'), u'name': u'user0'}
{u'age': 21, u'_id': ObjectId('4c456e8b499b14047e000002'), u'name': u'user1'}
{u'age': 23, u'_id': ObjectId('4c456e8b499b14047e000004'), u'name': u'user3'}
{u'age': 24, u'_id': ObjectId('4c456e8b499b14047e000005'), u'name': u'user4'}
{u'age': 25, u'_id': ObjectId('4c456e8b499b14047e000006'), u'name': u'user5'}
{u'age': 26, u'_id': ObjectId('4c456e8b499b14047e000007'), u'name': u'user6'}
{u'age': 27, u'_id': ObjectId('4c456e8b499b14047e000008'), u'name': u'user7'}
{u'age': 28, u'_id': ObjectId('4c456e8b499b14047e000009'), u'name': u'user8'}
{u'age': 29, u'_id': ObjectId('4c456e8b499b14047e00000a'), u'name': u'user9'}

&gt;&gt;&gt; db.users.remove()

&gt;&gt;&gt; for u in db.users.find(): print u
...
&gt;&gt;&gt;</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5296/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5296/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5296/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5296/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5296/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5296/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB: 1. Database</title>
		<link>http://www.iwanna.cn/archives/2010/09/17/5291/</link>
		<comments>http://www.iwanna.cn/archives/2010/09/17/5291/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 17:00:22 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=5291</guid>
		<description><![CDATA[mongo 是 MongoDB 自带的交互式 Javascript shell，用来对 Mongod 进行操作和管理的交互式环境。 使用 &#8220;./mongo &#8211;help&#8221; 可查看相关连接参数。 $ ./mongo --help MongoDB shell version: 1.5.3 usage: ./mongo [options] [db address] [file names (ending in .js)] db address can be: foo foo database on local machine 192.169.0.5/foo foo database on 192.168.0.5 machine 192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999 options: [...]]]></description>
			<content:encoded><![CDATA[<p>mongo 是 <a title="http://www.mongodb.org/" href="http://www.mongodb.org/" target="_blank">MongoDB</a> 自带的交互式  Javascript shell，用来对 Mongod 进行操作和管理的交互式环境。</p>
<p>使用 &#8220;./mongo &#8211;help&#8221;  可查看相关连接参数。</p>
<pre>$ ./mongo --help

<a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a> shell version: 1.5.3

usage: ./mongo [options] [db address] [file names (ending in .js)]

db address can be:
  foo                   foo <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">database</a> on local machine
  192.169.0.5/foo       foo <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">database</a> on 192.168.0.5 machine
  192.169.0.5:9999/foo  foo <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">database</a> on 192.168.0.5 machine on port 9999

options:
  --shell               run the shell after executing files
  --nodb                don't connect to mongod on startup - no 'db address'
                        arg expected
  --quiet               be less chatty
  --port arg            port to connect to
  --host arg            server to connect to
  --eval arg            evaluate javascript
  -u [ --username ] arg username for authentication
  -p [ --password ] arg password for authentication
  -h [ --help ]         show this usage information
  --version             show version information
  --ipv6                enable IPv6 support (disabled by default)

file names: a list of files to run. files have to end in .js and will exit after unless --shell is specified</pre>
<p><span id="more-5291"></span><br />
相关命令很多，要习惯使用 &#8220;help&#8221;。</p>
<pre>$ ./mongo

MongoDB shell version: 1.5.3
connecting to: test
type "help" for help

&gt; help
        help admin                   misc shell commands
        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time &gt;= 1ms
        use &lt;db name&gt;                set current database to &lt;db name&gt;
        db.help()                    help on DB methods
        db.foo.help()                help on collection methods
        db.foo.find()                list objects in collection foo
        db.foo.find( { a : 1 } )     list objects in foo where a == 1
        it                           result of the last line evaluated; use to further iterate
        exit                         quit the mongo shell</pre>
<p>(1)  MongoDB 会自动创建数据库(db)和集合(collection)，无需显式执行。</p>
<pre>$ ./mongo

MongoDB shell version: 1.5.3
connecting to: test
type "help" for help

&gt; show dbs // 查看当前数据库列表
admin
local

&gt; use blog // 切换到工作数据库
switched to db blog

&gt; db // 当前数据库
blog

&gt; for (var i = 0; i &lt; 10; i++) db.users.save({name : "user" + i, age : i}) // 插入数据

&gt; show dbs // 数据库 blog 被创建
admin
blog
local

&gt; show collections // 列表 users 被创建
system.indexes
users

&gt; db.copyDatabase("blog", "blog2") // 复制数据库
{ "ok" : true }

&gt; show dbs // 数据库 blog2 被创建
admin
blog
blog2
local

&gt; use blog2 // 切换到 blog2
switched to db blog2

&gt; show collections // 查看集合列表
system.indexes
users

&gt; db.users.find() // 查看被复制的数据
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981a"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981b"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981c"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981d"), "name" : "user3", "age" : 3 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981e"), "name" : "user4", "age" : 4 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac2981f"), "name" : "user5", "age" : 5 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac29820"), "name" : "user6", "age" : 6 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac29821"), "name" : "user7", "age" : 7 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac29822"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c33f8fcecf2b9320ac29823"), "name" : "user9", "age" : 9 }

&gt; db.dropDatabase() // 删除数据库 blog2
{ "dropped" : "blog2", "ok" : true }

&gt; show dbs // 确认数据库删除成功
admin
blog
local

&gt; use blog // 切换回 blog
switched to db blog

&gt; db.users.drop()  // 删除集合 users
true

&gt; show collections // 确认集合被删除
system.indexes

&gt; exit
bye</pre>
<p>(2) 还可以在多台服务器之间复制数据库。</p>
<pre>server64$ ./mongo

MongoDB shell version: 1.5.3
connecting to: test
type "help" for help

&gt; use blog
switched to db blog

&gt; for (var i = 0; i &lt; 10; i++) db.users.save({name : "user" + i, age : i})

&gt; use news
switched to db news

&gt; for (var i = 0; i &lt; 10; i++) db.articles.save({title : "title" + i})

&gt; show dbs
admin
blog
local
news

&gt; exit
bye</pre>
<p>准备好源数据库后，我们开始在复制。</p>
<pre>server32:$ ./mongo

MongoDB shell version: 1.5.4
connecting to: test

&gt; db.copyDatabase("blog", "blog", "192.168.1.202") // 从源服务器复制 blog 数据库
{ "ok" : true }

&gt; show dbs // 复制成功
admin
blog
local

&gt; use blog
switched to db blog

&gt; show collections
system.indexes
users

&gt; db.users.find()
{ "_id" : ObjectId("4c33fadb15b7f104d297e644"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e645"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e646"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e647"), "name" : "user3", "age" : 3 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e648"), "name" : "user4", "age" : 4 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e649"), "name" : "user5", "age" : 5 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64a"), "name" : "user6", "age" : 6 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64b"), "name" : "user7", "age" : 7 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64c"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64d"), "name" : "user9", "age" : 9 }

&gt; use news
switched to db news

&gt; db.cloneDatabase("192.168.1.202") // 从源服务器克隆当前数据库(news)
{ "ok" : true }

&gt; show dbs
admin
blog
local
news

&gt; show collections
articles
system.indexes

&gt; db.articles.find()
{ "_id" : ObjectId("4c33fb6215b7f104d297e64e"), "title" : "title0" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e64f"), "title" : "title1" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e650"), "title" : "title2" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e651"), "title" : "title3" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e652"), "title" : "title4" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e653"), "title" : "title5" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e654"), "title" : "title6" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e655"), "title" : "title7" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e656"), "title" : "title8" }
{ "_id" : ObjectId("4c33fb6215b7f104d297e657"), "title" : "title9" }

&gt; exit
bye</pre>
<p>(3) 当我们使用 use 切换到某个数据库时，变量 db 表示当前数据库。还可以用 getSisterDB()  函数获取其他数据库的引用。</p>
<pre>&gt; use admin
switched to db admin

&gt; db
admin

&gt; blog = db.getSisterDB("blog")
blog

&gt; blog.users.insert({name : "abc"})

&gt; blog.users.find({name : "abc"})
{ "_id" : ObjectId("4c3419b0492aa4cfbec11895"), "name" : "abc" }</pre>
<p>(4)  调用 fsync 命令，可以强制将内存中缓存数据写回数据库文件。如果不想等待，可添加 async 参数异步执行。</p>
<pre>&gt; use admin
switched to db admin

&gt; db.runCommand({fsync : 1})
{ "numFiles" : 6, "ok" : true }

&gt; db.runCommand({fsync : 1, async : true})
{ "numFiles" : 6, "ok" : true }</pre>
<p>(5)  某些时候需要锁定系统，阻塞所有写操作，诸如备份、整理数据库等等。锁定时读操作不受影响。</p>
<pre>$ ./mongo

MongoDB shell version: 1.5.3
connecting to: test
type "help" for help

&gt; use blog
switched to db blog

&gt; admin = db.getSisterDB("admin")
admin

&gt; admin.runCommand({fsync : 1, lock : 1}) // 锁定
{
        "info" : "now locked against writes, use db.$cmd.sys.unlock.findOne() to unlock",
        "ok" : true
}

&gt; db.users.find() // 读操作正常

{ "_id" : ObjectId("4c33fadb15b7f104d297e644"), "name" : "user0", "age" : 0 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e645"), "name" : "user1", "age" : 1 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e646"), "name" : "user2", "age" : 2 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e647"), "name" : "user3", "age" : 3 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e648"), "name" : "user4", "age" : 4 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e649"), "name" : "user5", "age" : 5 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64a"), "name" : "user6", "age" : 6 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64b"), "name" : "user7", "age" : 7 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64c"), "name" : "user8", "age" : 8 }
{ "_id" : ObjectId("4c33fadb15b7f104d297e64d"), "name" : "user9", "age" : 9 }

&gt; db.users.save({name : "xyz" }) // 写操作被阻塞，等待 ...</pre>
<p>另开启一个终端，解除 锁定。</p>
<pre>&gt; use admin
switched to db admin

&gt; db.$cmd.sys.unlock.findOne()
{ "ok" : 1, "info" : "unlock requested" }</pre>
<p>解除后，前一终端被阻塞的写操作正确返回。</p>
<p>(6)  调用 validate() 验证集合是否存在错误。</p>
<pre>&gt; db.users.validate()
{
        "ns" : "blog.users",
        "result" : "
validate
  firstExtent:0:2600 ns:blog.users
  lastExtent:0:23d00 ns:blog.users
  # extents:2
  datasize?:4640 nrecords?:116 lastExtentSize:9216
  padding:1
  first extent:
    loc:0:2600 xnext:0:23d00 xprev:null
    nsdiag:blog.users
    size:2304 firstRecord:0:26b0 lastRecord:0:2ec8
  116 objects found, nobj:116
  6496 bytes data w/headers
  4640 bytes data wout/headers
  deletedList: 0000000010000000000
  deleted: n: 1 size: 4672
  nIndexes:1
    blog.users.$_id_ keys:116
",
        "ok" : true,
        "valid" : true,
        "lastExtentSize" : 9216
}</pre>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/09/17/5291/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/09/17/5291/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/09/17/5291/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/09/17/5291/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/09/17/5291/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/09/17/5291/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>因为垄断形成，数据库市场将出现更多开源数据库</title>
		<link>http://www.iwanna.cn/archives/2010/07/21/4658/</link>
		<comments>http://www.iwanna.cn/archives/2010/07/21/4658/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 15:05:34 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[IT业内资讯]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4658</guid>
		<description><![CDATA[随着MySQL的命运飘忽不定，又涌现出许多开源数据库，包括了HadoopDB, Drizzle, MongoDB, Cassandra DB以及 CouchDB，这样的势头将在接下来的2010年持续下去。 NOSql概念值得关注。NOSQL适合高并发和超大规模数据的情况。NOt only sql，可见是关系数据的有益补充。具体可见此文章。 可以预见，PostgreSQL又将热起来。互联网上的选择，有时很忌讳商业公司。。就是这个缘故会造成部分(也难说是大部分)会选择 PostgreSQL。而成熟的开源免费的关系数据库，不多。PostgreSQL现在获得了很好的际遇。 MySQL联合创始人Monty Widenius提供了MySQL的分支MariaDB候选版本。据报道MariaDB 5.1完全兼容MySQL 5.1. MariaDB现在也获得了前所未有的际遇。 曾接受风投基金Y Combinator投资的创业公司Clustrix日前(2010.5.10)宣布，将推出可高度扩容的数据库解决方案，既具备与MySQL相似的功能 和可靠性，又能够扩容至存储数十亿条数据。Clustrix力图商业运用的努力也是开源数据库包括MariaDB要行进的方向。 可以预见，因为目前的mysql功能已经足够强大，换言之，针对网站和一般中小企业运用已经够用。针对初学者这个层面来讲，phpmyadmin功 不可没。开源的东西只要在宣传上加大力度，工具集成通过自身和第三方努力，在市场机遇方面把握住像现在这样的oracle收购sun控制mysql，抓住 sap收购sybase这样的一些机遇(这些时候大家的关注目标全部聚焦在数据库话题上,而且会出现许多变数)。同时也希望开源的东西可以有专业的公司提 供付费服务和商业推广。 不要忘记mssql是怎么获得大面积运用的，那就是mssql7.0和mssql2k的功劳，目前，mysql,PostgreSQL也足以支撑许 多一般运用。我想已经到达了当年mssql7.0和mssql2k开始挤占市场的时候了。sqlserver 的历史 开源的东西要放弃一些旧有的观点，比如100%命令模式，文档松散不求全，第三方工具零零散散缺乏组织，让人望而生畏。应多推GUI工具。实时整合 好的工具为一体。向window和mssql学习易用性，不要妄图用“专业性”来阻隔初学者。凭借已有的客户基础，轻而易举可以成就数据库领域的霸业。应 该推傻瓜安装包助推初学者掌握。须知，专业安装配置是专业程序员，管理员的事情。产品要推广必须要解决一般人的使用问题。如同在国内大家都知道的 ghost xp3对于普通电脑用户的作用一样。这种简化是必须的。就拿我自己来说，我通过mysql的phpmyadmin就很快掌握了对mysql的管理并作了简 单的学习测试。oracle我安装XE版，也很快学会了创建数据库，建表，导入导出数据，db2有java写的的GUI管理工具，与mssql的管理器类 似，也让我很快作了一个入门的学习。所以对他们就有一个简单的认识，而且颇具好感。这种好感是在产品推广中所必须要具备的。如果从命令模式开始学习，时间 会要很久，难度更高。印象不会很好，因为我一直是win过来的程序员和管理员。 更多的mysql分支和兼容数据库将被推出。兼容可以平滑地转移既有的客户群体。对用户而言分支可以获得更多的选择。对技术而言，分支可以另立门派 在技术上极大地提升而不受制于原有体系。 web时代成就了mysql数据库，但是今天来说，成熟的关系数据库或者说已经有基础的数据库系统，应该往关键运用，和大规模数据管理迈进。以往数 据论G，现在论T。mysql,PostgreSQL,MariaDB等不应该满足初学者应用其来开发一个留言本这样的简单需求而止步不前。 © 我想网 Akon 所有 , 2010. &#124; 永久链接 &#124; 没有评论 &#124; 提交到 Google Reader 鲜果 抓虾 Feed [...]]]></description>
			<content:encoded><![CDATA[<p>随着MySQL的命运飘忽不定，又涌现出许多开源数据库，包括了HadoopDB, Drizzle, <a href="http://www.iwanna.cn/tags/mongodb/" class="st_tag internal_tag" rel="tag" title="标签 MongoDB 下的日志">MongoDB</a>, Cassandra  DB以及 CouchDB，这样的势头将在接下来的2010年持续下去。</p>
<p>NOSql概念值得关注。NOSQL适合高并发和超大规模数据的情况。NOt only sql，可见是关系数据的有益补充。具体可见<a href="http://robbin.javaeye.com/blog/524977" target="_blank">此文章</a>。</p>
<p>可以预见，PostgreSQL又将热起来。互联网上的选择，有时很忌讳商业公司。。就是这个缘故会造成部分(也难说是大部分)会选择 PostgreSQL。而成熟的开源免费的关系数据库，不多。PostgreSQL现在获得了很好的际遇。<br />
<span id="more-4658"></span><!--more--><br />
MySQL联合创始人Monty Widenius提供了MySQL的分支MariaDB候选版本。据报道MariaDB  5.1完全兼容MySQL 5.1. MariaDB现在也获得了前所未有的际遇。</p>
<p>曾接受风投基金Y  Combinator投资的创业公司Clustrix日前(2010.5.10)宣布，将推出可高度扩容的数据库解决方案，既具备与MySQL相似的功能 和可靠性，又能够扩容至存储数十亿条数据。Clustrix力图商业运用的努力也是开源数据库包括MariaDB要行进的方向。</p>
<p>可以预见，因为目前的mysql功能已经足够强大，换言之，针对网站和一般中小企业运用已经够用。针对初学者这个层面来讲，phpmyadmin功 不可没。开源的东西只要在宣传上加大力度，工具集成通过自身和第三方努力，在市场机遇方面把握住像现在这样的oracle收购sun控制mysql，抓住 sap收购sybase这样的一些机遇(这些时候大家的关注目标全部聚焦在数据库话题上,而且会出现许多变数)。同时也希望开源的东西可以有专业的公司提 供付费服务和商业推广。</p>
<p>不要忘记mssql是怎么获得大面积运用的，那就是mssql7.0和mssql2k的功劳，目前，mysql,PostgreSQL也足以支撑许 多一般运用。我想已经到达了当年mssql7.0和mssql2k开始挤占市场的时候了。<a href="http://tech.it168.com/db/s/2006-10-16/200610161601038.shtml">sqlserver 的历史</a></p>
<p>开源的东西要放弃一些旧有的观点，比如100%命令模式，文档松散不求全，第三方工具零零散散缺乏组织，让人望而生畏。应多推GUI工具。实时整合 好的工具为一体。向window和mssql学习易用性，不要妄图用“专业性”来阻隔初学者。凭借已有的客户基础，轻而易举可以成就数据库领域的霸业。应 该推傻瓜安装包助推初学者掌握。须知，专业安装配置是专业程序员，管理员的事情。产品要推广必须要解决一般人的使用问题。如同在国内大家都知道的 ghost  xp3对于普通电脑用户的作用一样。这种简化是必须的。就拿我自己来说，我通过mysql的phpmyadmin就很快掌握了对mysql的管理并作了简 单的学习测试。oracle我安装XE版，也很快学会了创建数据库，建表，导入导出数据，db2有java写的的GUI管理工具，与mssql的管理器类 似，也让我很快作了一个入门的学习。所以对他们就有一个简单的认识，而且颇具好感。这种好感是在产品推广中所必须要具备的。如果从命令模式开始学习，时间 会要很久，难度更高。印象不会很好，因为我一直是win过来的程序员和管理员。</p>
<p>更多的mysql分支和兼容数据库将被推出。兼容可以平滑地转移既有的客户群体。对用户而言分支可以获得更多的选择。对技术而言，分支可以另立门派 在技术上极大地提升而不受制于原有体系。</p>
<p>web时代成就了mysql数据库，但是今天来说，成熟的关系数据库或者说已经有基础的数据库系统，应该往关键运用，和大规模数据管理迈进。以往数 据论G，现在论T。mysql,PostgreSQL,MariaDB等不应该满足初学者应用其来开发一个留言本这样的简单需求而止步不前。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/07/21/4658/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/07/21/4658/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/07/21/4658/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/07/21/4658/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/07/21/4658/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/07/21/4658/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>盘点2010年十大数据库漏洞</title>
		<link>http://www.iwanna.cn/archives/2010/06/21/4123/</link>
		<comments>http://www.iwanna.cn/archives/2010/06/21/4123/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 14:53:30 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4123</guid>
		<description><![CDATA[新的安全漏洞名单列出了可导致数据破坏的最常见的数据库问题。 对于Application Security公司新的十大数据库漏洞名单中所列出的问题，数据库管理员都非常熟悉。从预设密码的使用到补丁问题，数据库管理系统受到各种问题的困扰，使其容易受到攻击。当我报告数据库管理问题时，数据库管理员告诉我，他们都意识到这些常见的可能导致数据破坏的安全问题。但是，他们常说包含敏感数据的DBMS通常由许多不同的安全系统包围，这减少了攻击的威胁。 十大数据库漏洞 1.默认、空白及弱用户名/密码 2.SQL注入 3.广泛的用户和组权限 4.启用不必要的数据库功能 5.失效的配置管理 6.缓冲区溢出 7.特权升级 8.拒绝服务攻击 9.数据库未打补丁 10.敏感数据未加密 常见的安全做法 我记得我在2003年采访了Oracle数据库专家兼顾问Don Burleson。Don Burleson是一位著名的Oracle数据库顾问，他的许多建议几乎适用于任何数据库管理系统。他说，最常见的安全错误是由数据库管理员不能正确读取 安装说明导致的。默认密码和用户ID很容易被保留。数据库管理员没能很好地对数据库访问进行限制，这也增加了入侵的风险。 内部威胁 Securosis的首席技术官Adrian Lane最近概述了企业在部署数据库活动监控(DAM)软件时，可能会面临的一些问题。Echelon One的安全专家David Mortman写过一个专家技巧，概述了企业在减轻内部威胁方面，可以采取的措施。﻿ © 我想网 Akon 所有 , 2010. &#124; 永久链接 &#124; 没有评论 &#124; 提交到 Google Reader 鲜果 抓虾 Feed enhanced by Better Feed from Ozh]]></description>
			<content:encoded><![CDATA[<p><strong>新的安全漏洞名单列出了可导致数据破坏的最常见的数据库问题。</strong><br />
对于Application Security公司新的十大数据库漏洞名单中所列出的问题，数据库管理员都非常熟悉。从预设密码的使用到补丁问题，数据库管理系统受到各种问题的困扰，使其容易受到攻击。当我报告数据库管理问题时，数据库管理员告诉我，他们都意识到这些常见的可能导致数据破坏的安全问题。但是，他们常说包含敏感数据的DBMS通常由许多不同的安全系统包围，这减少了攻击的威胁。<br />
<span id="more-4123"></span><br />
<strong>十大数据库漏洞</strong><br />
1.默认、空白及弱用户名/密码<br />
2.SQL注入<br />
3.广泛的用户和组权限<br />
4.启用不必要的数据库功能<br />
5.失效的配置管理<br />
6.缓冲区溢出<br />
7.特权升级<br />
8.拒绝服务攻击<br />
9.数据库未打补丁<br />
10.敏感数据未加密<br />
<strong>常见的安全做法</strong><br />
我记得我在2003年采访了Oracle数据库专家兼顾问Don Burleson。Don  Burleson是一位著名的Oracle数据库顾问，他的许多建议几乎适用于任何数据库管理系统。他说，最常见的安全错误是由数据库管理员不能正确读取 安装说明导致的。默认密码和用户ID很容易被保留。数据库管理员没能很好地对数据库访问进行限制，这也增加了入侵的风险。<br />
<strong>内部威胁</strong><br />
Securosis的首席技术官Adrian Lane最近概述了企业在部署数据库活动监控(DAM)软件时，可能会面临的一些问题。Echelon  One的安全专家David Mortman写过一个专家技巧，概述了企业在减轻内部威胁方面，可以采取的措施。﻿</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/06/21/4123/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/06/21/4123/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/06/21/4123/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/06/21/4123/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/06/21/4123/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/06/21/4123/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>三种直接备份 WordPress 博客数据库的方法</title>
		<link>http://www.iwanna.cn/archives/2010/06/18/4073/</link>
		<comments>http://www.iwanna.cn/archives/2010/06/18/4073/#comments</comments>
		<pubDate>Fri, 18 Jun 2010 14:44:40 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4073</guid>
		<description><![CDATA[自从上次由于没有成功备份导致博客的大部分文章无法还原之后，我就更加小心博客的备份了，并且还尝试了多种的备份方法，以下是其中三种直接备份 WordPress 博客的方法。 所谓直接备份，是指不需要借助于 WordPress 插件、第三方服务或者程序代码，而直接通过 WordPress 后台或者 cPanel 备份，这样的备份方法是最安全的，只不过需要手动。 方法一：通过 WordPress 后台备份博客数据库 进入 WordPress 后台，点击“工具”选项下面的“导出”，然后在出现的页面点击“下载导出文件”就可以了。如果你的博客有多个作者，你还可以选择导出某一个作者的相关文 件。导出文件包括对应作者的全部文章、页面、评论、自定义域、分类目录和标签，但是不包括 WordPress 插件和小工具的设置。如果要备份插件和小工具的设置，则可以通过虚拟主机空间的 cPanel 控制面板来备份 WordPress 博客数据库： 方法二：通过 cPanel 备份博客数据库 进入 cPanel 之后，点击“文件”分类里面的“备份”，在出现页面的“部分备份”下面，选择需要备份的博客对应的 MySQL 数据库并下载。 除了通过 cPanel 的文件备份功能之外，你也可以通过 phpMyAdmin 的导出功能进行 WordPress 博客的数据库备份： 方法三：通过 phpMyAdmin 备份博客数据库 点击 cPanel “数据库” 分类下面的 “phpMyAdmin”，在出现的页面点击博客对应的数据库，然后点击工具栏上的“导出”，并在下一页面的“另存为文件”一栏下面选择“gzip压 缩”，然后点击“执行”，就可以把数据库下载到你的电脑硬盘了。 通常情况下我会选择第二种方法备份 WordPress 博客的数据库，因为备份的数据比第一种方法要全面，而速度则比第三种方法要快。不过，如果只是要把一个 WordPress 博客的文章转移到另外一个 WordPress 博客上，那么就用第一种方法。你是通过哪一种方法备份 WordPress [...]]]></description>
			<content:encoded><![CDATA[<p>自从上次由于没有成功备份导致博客的大部分文章无法还原之后，我就更加小心博客的备份了，并且还尝试了多种的备份方法，以下是其中三种直接备份 <a href="http://www.iwanna.cn/tags/wordpress-php-develope/" class="st_tag internal_tag" rel="tag" title="标签 Wordpress 下的日志">WordPress</a> 博客的方法。</p>
<p>所谓<strong><a href="http://www.iwanna.cn/archives/2010/06/18/4073/" title="三种直接备份 WordPress 博客数据库的方法">直接备份</a></strong>，是指不需要借助于 WordPress 插件、第三方服务或者程序代码，而直接通过 WordPress 后台或者 cPanel 备份，这样的备份方法是最安全的，只不过需要手动。</p>
<p><strong>方法一：通过 WordPress 后台备份博客数据库</strong></p>
<p><img title="wordpress-export" src="http://images.uheed.com/iwanna/2010/06/18/wordpress-export.jpg" alt="备份 WordPress 博客数据库" width="540px" height="285px" /><br />
<span id="more-4073"></span><br />
进入 WordPress  后台，点击“工具”选项下面的“导出”，然后在出现的页面点击“下载导出文件”就可以了。如果你的博客有多个作者，你还可以选择导出某一个作者的相关文 件。导出文件包括对应作者的全部文章、页面、评论、自定义域、分类目录和标签，但是不包括 WordPress  插件和小工具的设置。如果要备份插件和小工具的设置，则可以通过虚拟主机空间的 cPanel 控制面板来备份 WordPress 博客数据库：</p>
<p><strong>方法二：通过 cPanel 备份博客数据库</strong></p>
<p><img title="cpanel-backup" src="http://images.uheed.com/iwanna/2010/06/18/cpanel-backup.jpg" alt="备份 WordPress 博客数据库" width="539px" height="225px" /></p>
<p>进入 cPanel 之后，点击“文件”分类里面的“备份”，在出现页面的“部分备份”下面，选择需要备份的博客对应的 MySQL  数据库并下载。</p>
<p>除了通过 cPanel 的文件备份功能之外，你也可以通过 phpMyAdmin 的导出功能进行 WordPress 博客的数据库备份：</p>
<p><strong>方法三：通过 phpMyAdmin 备份博客数据库</strong></p>
<p><img title="phpmyadmin-backup" src="http://images.uheed.com/iwanna/2010/06/18/phpmyadmin-backup.jpg" alt="备份 WordPress 博客数据库" width="540px" height="196px" /></p>
<p>点击 cPanel “数据库” 分类下面的  “phpMyAdmin”，在出现的页面点击博客对应的数据库，然后点击工具栏上的“导出”，并在下一页面的“另存为文件”一栏下面选择“gzip压 缩”，然后点击“执行”，就可以把数据库下载到你的电脑硬盘了。</p>
<p>通常情况下我会选择第二种方法备份 WordPress  博客的数据库，因为备份的数据比第一种方法要全面，而速度则比第三种方法要快。不过，如果只是要把一个 WordPress 博客的文章转移到另外一个  WordPress 博客上，那么就用第一种方法。你是通过哪一种方法备份 WordPress 博客数据库的呢？如果你还有其他的备份方法，欢迎分享。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/06/18/4073/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/06/18/4073/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/06/18/4073/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/06/18/4073/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/06/18/4073/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/06/18/4073/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何通过 AutoMySQLBackup 备份你的博客数据库</title>
		<link>http://www.iwanna.cn/archives/2010/06/18/4071/</link>
		<comments>http://www.iwanna.cn/archives/2010/06/18/4071/#comments</comments>
		<pubDate>Fri, 18 Jun 2010 14:37:11 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4071</guid>
		<description><![CDATA[通过服务器直接备份博客数据库虽然最安全，但是需要手动不方便；通过 WordPress 插件备份虽然可以全自动，但是可能会出现问题。所以，如果能够把数据库备份到服务器，同时也备份到邮箱，不需要安装任何插件，并且一切都是自动 完成的，那就好了。 事实上，AutoMySQLBackup 程序是可以实现这个想法的，虽然并不适合所有的服务器。下面先介绍 AutoMySQLBackup 程序的使用方法，然后再说说它的不足之处。 一、通过 AutoMySQLBackup 备份博客数据库的具体步骤： 第一步. 下载 AutoMySQLBackup 文件 下载地址：AutoMySQLBackup 下载到的文件是这样的： automysqlbackup.sh.2.5 把以上文件重命名为 “automysqlbackup.sh”。 第二步. 在服务器上创建一个备份文件夹 这个文件夹是用来储存你备份的数据库的，文件夹的名字可以随意。文件夹可以放到博客服务器的任何目录，但是为了安全起见，最好放在根目录，也就是和 “public_html” 文件夹放在一起，那样别人就访问不到你的备份数据库了。以下就以新文件夹的路径是“/home/young/backups”作为例子。 第三步. 上传 AutoMySQLBackup 文件 把 automysqlbackup.sh 文件上传到新建的文件夹 “backups”。你可以通过 FTP 软件上传，也可以通过 cPanel 上传。不过最好通过 cPanel 上传，因为就一个文件并且下面还要在 cPanel 上操作。 第四步. 更改许可 通过 cPanel 的“文件管理器” 找到并选择 AutoMySQLBackup 文件，点击“更改许可”，然后把许可属性改为“755”。 第五步. 修改 AutoMySQLBackup 文件 更改许可并保存之后，点击编辑。虽然 automysqlbackup.sh [...]]]></description>
			<content:encoded><![CDATA[<p>通过服务器直接备份博客数据库虽然最安全，但是需要手动不方便；通过 <a href="http://www.iwanna.cn/tags/wordpress-php-develope/" class="st_tag internal_tag" rel="tag" title="标签 Wordpress 下的日志">WordPress</a> 插件备份虽然可以全自动，但是可能会出现问题。所以，如果能够把数据库备份到服务器，同时也备份到邮箱，不需要安装任何插件，并且一切都是自动 完成的，那就好了。</p>
<p>事实上，AutoMySQLBackup 程序是可以实现这个想法的，虽然并不适合所有的服务器。下面先介绍 AutoMySQLBackup  程序的使用方法，然后再说说它的不足之处。</p>
<h2>一、通过 AutoMySQLBackup 备份博客数据库的具体步骤：</h2>
<p><strong>第一步. 下载 AutoMySQLBackup 文件</strong></p>
<p>下载地址：<a href="http://sourceforge.net/projects/automysqlbackup/">AutoMySQLBackup</a><br />
<span id="more-4071"></span><br />
下载到的文件是这样的：</p>
<blockquote><p><code>automysqlbackup.sh.2.5</code></p></blockquote>
<p>把以上文件重命名为 “automysqlbackup.sh”。</p>
<p><strong>第二步. 在服务器上创建一个备份文件夹</strong></p>
<p>这个文件夹是用来储存你备份的数据库的，文件夹的名字可以随意。文件夹可以放到博客服务器的任何目录，但是为了安全起见，最好放在根目录，也就是和 “public_html”  文件夹放在一起，那样别人就访问不到你的备份数据库了。以下就以新文件夹的路径是“/home/young/backups”作为例子。</p>
<p><strong>第三步. 上传 AutoMySQLBackup 文件</strong></p>
<p>把 automysqlbackup.sh 文件上传到新建的文件夹 “backups”。你可以通过 FTP 软件上传，也可以通过  cPanel 上传。不过最好通过 cPanel 上传，因为就一个文件并且下面还要在 cPanel 上操作。</p>
<p><strong>第四步. 更改许可</strong></p>
<p>通过 cPanel 的“文件管理器” 找到并选择 AutoMySQLBackup 文件，点击“更改许可”，然后把许可属性改为“755”。</p>
<p><strong>第五步. 修改 AutoMySQLBackup 文件</strong></p>
<p>更改许可并保存之后，点击编辑。虽然 automysqlbackup.sh 文件里面的内容很多，但是你需要修改的只有以下7个地方：</p>
<blockquote><p># Username to access the MySQL server e.g. dbuser<br />
USERNAME=这里填你的博客数据库用户名（1）</p>
<p># Username to access the MySQL server e.g. password<br />
PASSWORD=这里填你的博客数据库用户名的密码 （2）</p>
<p># Host name (or IP address) of MySQL server e.g localhost<br />
DBHOST=localhost</p>
<p># List of DBNAMES for Daily/Weekly Backup e.g. &#8220;DB1 DB2 DB3&#8243;<br />
DBNAMES=&#8221;这里填你的博客数据库名称，如果有多个数据库，每两个数据库名称中间用一个空格隔开，例如‘数据库1 数据库2  数据库3’，当然，你也可以填‘all’。&#8221; （3）</p>
<p># Backup directory location e.g /backups<br />
BACKUPDIR=&#8221;这里填你新建的文件夹路径，例如‘/home/young/backups’。&#8221;（4）</p>
<p># Mail setup<br />
# What would you like to be mailed to you?<br />
# &#8211; log   : send only log file<br />
# &#8211; files : send log file and sql files as attachments (see docs)<br />
# &#8211; stdout : will simply output the log to the screen if run manually.<br />
# &#8211; quiet : Only send logs if an error occurs to the MAILADDR.<br />
MAILCONTENT=&#8221;如果你想并且可以把备份的数据库发到邮箱，这里就填‘files’，否则，就填‘log’、‘stout’和‘quiet’其 中的任意一个。&#8221; （5）</p>
<p># Set the maximum allowed email size in k. (4000 = approx 5MB email  [see docs])<br />
MAXATTSIZE=&#8221;这里填允许发送邮件的最大尺寸，默认为4MB。&#8221; （6）</p>
<p># Email Address to send mail to? (user@domain.com)<br />
MAILADDR=&#8221;这里填你接收备份数据的邮箱地址&#8221; （7）</p></blockquote>
<p>以上标注的7个地方除了 （5）和（6）可以不改之外，其他都是需要更改的，另外，双引号是要保留的。</p>
<p>AutoMySQLBackup 文件修改完并保存之后，接下来的就简单了。</p>
<p><strong>第六步. 创建一个时钟守护作业</strong></p>
<p>打开 cPanel “高级”选项里面的“时钟守护作业（Cron  jobs)”，输入你的邮箱地址，设置要备份的时间，可以简单地设置为每天备份一次，也可以设置为具体哪一天备份。备份时间设置好之后，在  Command 一栏输入 AutoMySQLBackup 文件的路径，例如：</p>
<blockquote><p>/home/young/backups/automysqlbackup.sh</p></blockquote>
<p>点击 Add New Cron Job 就完成了整个通过 AutoMySQLBackup 备份你博客数据库的操作。</p>
<h2>二、AutoMySQLBackup 程序的不足之处</h2>
<p>通过 AutoMySQLBackup + Cron Job  的方式来备份博客数据库，可以少安装一个插件，可以同时备份多个数据库，还可以有双重保障——备份数据库可以保存在服务器上同时也可以发到邮箱。但是只有 安装了 <a href="http://www.mutt.org/">Mutt</a> 程序的服务器才可以把数据库发到邮箱。碰巧精品博客所用的服务器 BlueHost 不支持 Mutt，所以通过  AutoMySQLBackup，我只能把精品博客的数据库备份到服务器，而无法备份到邮箱。</p>
<p>如果你有在不支持 Mutt 的服务器上通过 AutoMySQLBackup  备份数据库到邮箱的解决方法，或者有可以把博客数据库备份到邮箱的其他程序，欢迎分享。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/06/18/4071/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/06/18/4071/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/06/18/4071/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/06/18/4071/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/06/18/4071/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/06/18/4071/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>10 大免费 WordPress 博客数据库备份插件</title>
		<link>http://www.iwanna.cn/archives/2010/06/18/4069/</link>
		<comments>http://www.iwanna.cn/archives/2010/06/18/4069/#comments</comments>
		<pubDate>Fri, 18 Jun 2010 14:34:30 +0000</pubDate>
		<dc:creator>seasun</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.iwanna.cn/?p=4069</guid>
		<description><![CDATA[直接备份 WordPress 博客数据库的方法虽然比较安全，但是也比较麻烦，因为你每次都要手动操作。于是，有人想到了通过使用插件的方法来自动备份 WordPress 博客的数据库。 WordPress 博客数据库备份插件不少，下面 10 个则是其中的佼佼者，它们都是免费的并且都兼容于 WordPress 2.9.2： 1. WordPress Database Backup 安装并激活 WordPress Database Backup 插件之后，你会在 WordPress 控制面板的“工具”分类下面看到“备份”选项，点击就可以对插件进行设置。你可以选择要备份的数据表，然后通过设定“定时备份”把备份数据库发到你的邮箱，当然，你也可以选择“立即备份”，把数据库备份到你的电脑硬盘。 2. WordPress Online Automated Backup 到 wordpressbackup.com 网站注册一个帐号，并添加你的博客（一个帐号一个博客），接着下载并安装 WordPress Online Automated Backup 插件，然后按照要求对插件进行设置，完了之后，该插件就会自动备份你的博客数据库到 wordpressbackup.com 网站，备份时间是经常而不定时的，免费帐户数据库的最大容量为 5M。 3. BackWPup BackWPup 可以备份数据库，也可以备份 WordPress 文件夹里面的文件，还可以优化数据表。备份的数据库会保存在博客所在服务器，同时也可以下载或者发送到邮箱，支持自动备份。 4. DBC Backup DBC Backup 是把你的 WordPress 博客数据库备份到博客所在的服务器，你可以随时进行手动备份，也可以设定自动备份的时间；你可以选择自动删除所有的旧备份，也可以选择不删除或者删除多少 天之后的备份；你可以选择压缩备份文件，也可以选择不压缩文件。 5. myEASYbackup [...]]]></description>
			<content:encoded><![CDATA[<p>直接备份 <a href="http://www.iwanna.cn/tags/wordpress-php-develope/" class="st_tag internal_tag" rel="tag" title="标签 Wordpress 下的日志">WordPress</a> 博客数据库的方法虽然比较安全，但是也比较麻烦，因为你每次都要手动操作。于是，有人想到了通过使用插件的方法来自动备份 <a href="http://www.iwanna.cn/tags/wordpress-php-develope/" class="st_tag internal_tag" rel="tag" title="标签 Wordpress 下的日志">WordPress</a> 博客的数据库。</p>
<p><strong><a title="10 大免费 WordPress 博客数据库备份插件" href="http://www.iwanna.cn/archives/2010/06/18/4069/">WordPress 博客数据库备份插件</a></strong>不少，下面 10 个则是其中的佼佼者，它们都是免费的并且都兼容于 WordPress 2.9.2：</p>
<p><strong>1. <a id="aptureLink_Ew71N3dtW0" href="http://wordpress.org/extend/plugins/wp-db-backup/">WordPress  Database Backup</a></strong></p>
<p><img title="WordPress-Database-Backup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/WordPress-Database-Backup.jpg" alt="WordPress backup" width="537px" height="388px" /><br />
<span id="more-4069"></span><br />
安装并激活 WordPress <a href="http://www.iwanna.cn/tags/db/" class="st_tag internal_tag" rel="tag" title="标签 Database 下的日志">Database</a> Backup 插件之后，你会在 WordPress  控制面板的“工具”分类下面看到“备份”选项，点击就可以对插件进行设置。你可以选择要备份的数据表，然后通过设定“定时备份”把备份数据库发到你的邮箱，当然，你也可以选择“立即备份”，把数据库备份到你的电脑硬盘。</p>
<p><strong>2. <a id="aptureLink_UXXhsOaiFY" href="http://wordpress.org/extend/plugins/wordpressbackup/">WordPress  Online Automated Backup</a></strong></p>
<p><img title="wordpressbackup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/wordpressbackup.jpg" alt="WordPress backup" width="537px" height="291px" /></p>
<p>到 wordpressbackup.com 网站注册一个帐号，并添加你的博客（一个帐号一个博客），接着下载并安装 WordPress  Online Automated Backup 插件，然后按照要求对插件进行设置，完了之后，该插件就会自动备份你的博客数据库到  wordpressbackup.com 网站，备份时间是经常而不定时的，免费帐户数据库的最大容量为 5M。</p>
<p><strong>3. <a id="aptureLink_I9zKFQbiC6" href="http://wordpress.org/extend/plugins/backwpup/">BackWPup</a></strong></p>
<p><img title="BackWPup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/BackWPup.jpg" alt="WordPress backup" width="537px" height="313px" /></p>
<p>BackWPup 可以备份数据库，也可以备份 WordPress  文件夹里面的文件，还可以优化数据表。备份的数据库会保存在博客所在服务器，同时也可以下载或者发送到邮箱，支持自动备份。</p>
<p><strong>4. <a id="aptureLink_Fo77JzUgPx" href="http://wordpress.org/extend/plugins/dbc-backup/">DBC Backup</a></strong></p>
<p><img title="dbc-backup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/b6dbc-backup.jpg" alt="WordPress backup" width="540px" height="282px" /></p>
<p>DBC Backup 是把你的 WordPress  博客数据库备份到博客所在的服务器，你可以随时进行手动备份，也可以设定自动备份的时间；你可以选择自动删除所有的旧备份，也可以选择不删除或者删除多少 天之后的备份；你可以选择压缩备份文件，也可以选择不压缩文件。</p>
<p><strong>5. <a id="aptureLink_Stzh129WSo" href="http://wordpress.org/extend/plugins/myeasybackup/">myEASYbackup</a></strong></p>
<p><img title="myEASYbackup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/myEASYbackup.jpg" alt="WordPress backup" width="540px" height="230px" /></p>
<p>myEASYbackup 的操作也很简单，安装并激活插件之后，就可以直接进行备份了，除了备份 WordPress  博客数据库之外，还可以备份 WordPress 的安装文件，备份文件会保存在你的服务器，但是你也可以在 WordPress  后台直接下载到你的电脑。该插件目前不支持自动备份。</p>
<p><strong>6. <a id="aptureLink_fwnsdC8z6Q" href="http://wordpress.org/extend/plugins/wponlinebackup/">Online Backup  for WordPress</a> </strong></p>
<p><img title="Online-Backup-for-WordPress" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/Online-Backup-for-WordPress.jpg" alt="WordPress backup" width="540px" height="206px" /></p>
<p>在使用 Online Backup for WordPress 之前，你需要先到插件开发者 BTE 那里注册，免费注册后你可以获得 50M  的存储空间，你可以把 WordPress  博客的数据库备份到那个空间，也可以把数据库下载到你的电脑或者备份到你的邮箱，可以设置自动备份时间，也可以马上进行手动备份。</p>
<p><strong>7. <a id="aptureLink_9CMF5xlztc" href="http://wordpress.org/extend/plugins/wordpress-ez-backup/">WordPress  EZ Backup</a></strong></p>
<p><img title="wordpress-ez-backup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/wordpress-ez-backup.jpg" alt="WordPress backup" width="537px" height="280px" /></p>
<p>WordPress EZ Backup 可以把你 WordPress  博客的任意文件夹以及数据库备份到博客服务器上。除了手动备份，你也可以进行自动备份，不过 WordPress EZ Backup  需要设置的地方比较多。</p>
<p><strong>8. <a id="aptureLink_rPLFwlxkjn" href="http://wordpress.org/extend/plugins/bei-fen/">Bei Fen</a></strong></p>
<p><img title="beifen" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/beifen.jpg" alt="WordPress backup" width="537px" height="284px" /></p>
<p>Bei Fen 插件可以把你 WordPress  的文件以及/或者数据库备份到博客的服务器，你可以手动进行立即备份，也可以设定自动备份时间。备份数据库可以直接在 WordPress  后台删除或者恢复。</p>
<p><strong>9. <a id="aptureLink_VpzdlXEKn8" href="http://wordpress.org/extend/plugins/remote-database-backup/">Remote  Database Backup</a></strong></p>
<p><img title="Remote-Database-Backup" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/Remote-Database-Backup.jpg" alt="WordPress backup" width="540px" height="226px" /></p>
<p>Remote Database Backup 插件可以说是 WordPress Database Backup 的简化，你可以直接在  WordPress 管理后台备份并下载数据库，但是不可以自动备份数据库，也不可以设置把备份的数据库发送到邮箱。</p>
<p><strong>10. <a id="aptureLink_yZPDOjdBsK" href="http://wordpress.org/extend/plugins/wp-dbmanager/">WP-DBManager</a></strong></p>
<p><img title="wp-dbmanager" src="http://images.uheed.com/iwanna/2010/06/18/wordpress_db_back/wp-dbmanager.jpg" alt="WordPress backup" width="540px" height="209px" /></p>
<p>WP-DBManager 的功能相当丰富，你可以把数据库备份到服务器、邮箱或者电脑硬盘，可以设置自动备份，可以修复、优化、清空甚至删除数据表，还可以删除或者还原备份到博客所在服务器的数据库。</p>
<p>编辑后注：<a href="http://www.iwanna.cn/">我想网</a>一直通过 WordPress Database Backup 这个插件来备份博客数据库，推荐大家使用，我通常会把备份的时间定在午夜之后操作，因为这个时间往往都是网站访问量最低的时间段，可以有效确保WordPress站点的正常运行。</p>
<hr />
<p>© <a href="http://www.iwanna.cn">我想网</a> Akon 所有 , 2010. |
<a href="http://www.iwanna.cn/archives/2010/06/18/4069/">永久链接</a> |
<a href="http://www.iwanna.cn/archives/2010/06/18/4069/#comments">没有评论</a> |
提交到
<a rel="nofollow" target="_blank" href="http://www.google.com/reader/view/feed/http://www.iwanna.cn/archives/2010/06/18/4069/">Google Reader</a>
<a rel="nofollow" target="_blank" href="http://www.xianguo.com/subscribe.php?url=http://www.iwanna.cn/archives/2010/06/18/4069/">鲜果</a>
<a rel="nofollow" target="_blank" href="http://www.zhuaxia.com/add_channel.php?url=http://www.iwanna.cn/archives/2010/06/18/4069/">抓虾</a>
<hr />
<script type="text/javascript"><!--
google_ad_client = "pub-2057344547305288";
/* 336x280,iwanna feed,created 10/3/10 */
google_ad_slot = "9738886183";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<hr />
</p>
<p><small>Feed enhanced by <a href='http://planetozh.com/blog/my-projects/wordpress-plugin-better-feed-rss/'>Better Feed</a> from  <a href='http://planetozh.com/blog/'>Ozh</a></small></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iwanna.cn/archives/2010/06/18/4069/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

