[原创] Java实现MongoDB数据导入及自定义复杂查询函数

本实验主要包含三部分:

1、从源文件中加载数据至数据库中。

2、从数据库中查询数据验证加载是否完成。

3、自定义特定的查询函数。

这么看,Java也是支持Mongo中的原生语法,不赖!对比Python来说,代码量稍多了些,

毕竟一个是弱类型、非防御式编程,一个是强类型、防御式编程,Java毕竟不擅长用来编写脚本。

测试数据:

wubiao,chinese,91

wubiao,math,11

zhangsan,english,40

zhangsan,politics,95

zhangsan,physics,84

lisi,computer,92

lisi,english,95

lisi,chinese,88

wanger,mathematics,90

wanger,english,60

wanger,chinese,40

zhaoliu,economics,96

zhaoliu,computer,94

复制代码

计划数据库中存储数据结构为:

{ "course" : "chinese", "score" : 91, "name" : "wubiao" }

{ "course" : "math", "score" : 11, "name" : "wubiao" }

{ "course" : "english", "score" : 40, "name" : "zhangsan" }

{ "course" : "politics", "score" : 95, "name" : "zhangsan" }

{ "course" : "physics", "score" : 84, "name" : "zhangsan" }

{ "course" : "computer", "score" : 92, "name" : "lisi" }

{ "course" : "english", "score" : 95, "name" : "lisi" }

{ "course" : "chinese", "score" : 88, "name" : "lisi" }

{ "course" : "mathematics", "score" : 90, "name" : "wanger" }

{ "course" : "english", "score" : 60, "name" : "wanger" }

{ "course" : "chinese", "score" : 40, "name" : "wanger" }

{ "course" : "economics", "score" : 96, "name" : "zhaoliu" }

{ "course" : "computer", "score" : 94, "name" : "zhaoliu" }

复制代码

源文件每行数据包含姓名、课程、得分,以逗号分隔。对于这几条数据来说,完全可以用Mongo客户端手段插入,

但是如果几十万条,几百万条呢?不可能一行一行自己插,所以必须要借助工具或脚本实现。

本次查找的需求是:找出有至少两门课程成绩达到90以上的学员名单。这只是个很简单的需求,其实我们完全可以很轻松的自定义各种复杂的查询函数。

环境:

OS:CentOS 5.9 32bit

JDK:jdk1.6.0_29

MongoDB: 2.2.3

driver:mongo-2.10.1.jar

如果MongoDB还没安装配置好,可以参考:

CentOS下使用yum安装MongoDB及相关配置http://f.dataguru.cn/forum.php?mod=viewthread&tid=56377&fromuid=4771

如果不了解MongoDB的java驱动可以参考:

JAVA操作MongoDB--mongodb/mongo-java-driver

http://f.dataguru.cn/forum.php?mod=viewthread&tid=94472&fromuid=4771

OK,开搞。。

先启动mongod

[root@biao ~]# mongod -f /etc/mongod.conf

all output going to: /mongodb/log/mongodb.log

forked process: 32465

child process started successfully, parent exiting

[root@biao ~]# service mongod status

mongod (pid 32465) is running...

[root@biao ~]# ps aux|grep mongod

root     32465  0.6  0.7 118388 22008 ?        Sl   02:00   0:00 mongod -f /etc/mongod.conf

root     32559  0.0  0.0   4032   684 pts/11   R+   02:01   0:00 grep mongod

[root@biao ~]# netstat -aux|grep mongod

unix  2      [ ACC ]     STREAM     LISTENING     519024 /tmp/mongodb-27017.sock

复制代码

如上所示,mongod启动成功,监听端口为27017。

Java代码:

package com.wubiao.mongo;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.net.UnknownHostException;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import com.mongodb.BasicDBObject;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.DBCursor;

import com.mongodb.DBObject;

import com.mongodb.MongoClient;

public class Test {

public static void main(String[] args) {

Test test = new Test();

DBCollection dbCollection = null;

try {

dbCollection = test.getCollection(null, "test_java", "stu");

} catch (UnknownHostException e) {

e.printStackTrace();

}

// 源文件路径为/root/Desktop/data.txt

String separator = File.separator;

File file = new File(separator + "root" + separator + "Desktop" + separator + "data.txt");

//加载数据,并返回成功加载的行数

test.loadData(file, dbCollection);

//打印所有文档

test.printAllDocs(dbCollection);

//查找至少两门课成绩达到90以上的同学名单

test.findNameByTwoScore(dbCollection);

}

/**

* 获取要操作的集合

* @param mongoClient

* @param database

* @param collection

* @return

* @throws UnknownHostException

*/

public DBCollection getCollection(MongoClient mongoClient, String database, String collection) throws UnknownHostException {

if (mongoClient == null) {

//建立连接

mongoClient = new MongoClient();

}

//获取数据库

DB db = mongoClient.getDB(database);

//获取集合

DBCollection dbCollection = db.getCollection(collection);

return dbCollection;

}

/**

* 从源文件中加载数据至数据库中

* @param file 源数据文件

* @param dbCollection 要加载至的集合

* @return 返回成功加载的行数,也就是文档数

*/

public int loadData(File file,DBCollection dbCollection) {

if (file == null || !file.isFile() || !file.exists()) {

return 0;

}

BufferedReader reader = null;

ArrayList docs = new ArrayList();

try {

reader = new BufferedReader(new FileReader(file));

String line = null;

System.out.println("***下列行将会作为文档被插入至数据库中...***");

while ((line = reader.readLine()) != null) {

System.out.println(line);

String[] lines = line.split(",");

BasicDBObject doc = new BasicDBObject();

doc.append("name", lines[0]);

doc.append("course", lines[1]);

doc.append("score", Integer.valueOf(lines[2]));

docs.add(doc);

}

if (docs.size() > 0) {

dbCollection.insert(docs);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

System.out.println("***总计有" + docs.size() + "行作为文档已被插入数据库中...***");

return docs.size();

}

/**

* 打印集合中包含的所有文档

* @param dbCollection 要查询的集合

*/

public static void printAllDocs(DBCollection dbCollection) {

//获取当前集合中所有对象的游标

DBCursor dbCursor = dbCollection.find();

//迭代打印所有对象

System.out.println("****当前集合包含的所有文档 begin****");

while (dbCursor.hasNext()) {

System.out.println("* " + dbCursor.next());

}

System.out.println("****当前集合包含的所有文档 end******");

}

/**

* 在集合中查询至少两门课程成绩大于90的学员

* @param dbCollection 要查询的集合

* @return 查询符合条件的学员姓名

*/

public List findNameByTwoScore(DBCollection dbCollection) {

//获取所有学员的姓名

ArrayList AllNames = (ArrayList) dbCollection.distinct("name");

//要返回的学员姓名列表

ArrayList names = new ArrayList();

//迭代学员姓名,按学员姓名与成绩大于90作为查询条件

//当查询所得的结果大于等于2时,表示符合查询,返回

for (Iterator iter = AllNames.iterator(); iter.hasNext(); ) {

String name = iter.next();

DBCursor cursor = dbCollection.find(new BasicDBObject("name",name).append("score", new BasicDBObject("$gt",90)));

if (cursor.count() > 1) {

names.add(name);

}

}

System.out.println("***至少两门课成绩达到90以上的同学名单:");

System.out.println(names);

return names;

}

}

/*

控制台打印信息:

***下列行将会作为文档被插入至数据库中...***

wubiao,chinese,91

wubiao,math,11

zhangsan,english,40

zhangsan,politics,95

zhangsan,physics,84

lisi,computer,92

lisi,english,95

lisi,chinese,88

wanger,mathematics,90

wanger,english,60

wanger,chinese,40

zhaoliu,economics,96

zhaoliu,computer,94

***总计有13行作为文档已被插入数据库中...***

****当前集合包含的所有文档 begin****

* { "_id" : { "$oid" : "5167513de4b0619e77863b43"} , "name" : "wubiao" , "course" : "chinese" , "score" : 91}

* { "_id" : { "$oid" : "5167513de4b0619e77863b44"} , "name" : "wubiao" , "course" : "math" , "score" : 11}

* { "_id" : { "$oid" : "5167513de4b0619e77863b45"} , "name" : "zhangsan" , "course" : "english" , "score" : 40}

* { "_id" : { "$oid" : "5167513de4b0619e77863b46"} , "name" : "zhangsan" , "course" : "politics" , "score" : 95}

* { "_id" : { "$oid" : "5167513de4b0619e77863b47"} , "name" : "zhangsan" , "course" : "physics" , "score" : 84}

* { "_id" : { "$oid" : "5167513de4b0619e77863b48"} , "name" : "lisi" , "course" : "computer" , "score" : 92}

* { "_id" : { "$oid" : "5167513de4b0619e77863b49"} , "name" : "lisi" , "course" : "english" , "score" : 95}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4a"} , "name" : "lisi" , "course" : "chinese" , "score" : 88}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4b"} , "name" : "wanger" , "course" : "mathematics" , "score" : 90}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4c"} , "name" : "wanger" , "course" : "english" , "score" : 60}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4d"} , "name" : "wanger" , "course" : "chinese" , "score" : 40}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4e"} , "name" : "zhaoliu" , "course" : "economics" , "score" : 96}

* { "_id" : { "$oid" : "5167513de4b0619e77863b4f"} , "name" : "zhaoliu" , "course" : "computer" , "score" : 94}

****当前集合包含的所有文档 end******

***至少两门课成绩达到90以上的同学名单:

[lisi, zhaoliu]

*/

复制代码

依然照顾到有些童鞋可能不太熟悉Java,依然尝试着在代码中加入了很详细的注释,依然应该很详细了。

代码除了连接、获取数据库、获取集合之外,包含三部分:

1、从源文件中加载数据至数据库中。

2、查询所有的文档验证导入的数据。

3、实现自定义查询。

这三部分是相对独立的,分别有Test类中的三个方法实现,具体哪个方法执行哪些工作不用解释了,方法名就看得出来。

三个方法可以一起执行,也可以分别执行,不想执行的部分在main方法中注释掉就好了,用双斜杠//注释即可。

一改以往的作风,这次稍稍的封装了下,谁叫咱是喜欢面向对象的码农呢。。。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容