[Groovy] 一种很酷的语言Groovy,可以简单地处理MongoDB -Groovy的应用篇-

这是G* Advent Calendar 2015第八天的文章。

首先

在昨天的文章中,我展示了如何使用Groovy来处理MongoDB的基本知识。
这次,让我们进一步使用Groovy的功能来更深入地了解它的魅力!
如果你时间有限的话,我也在最后附上了整个代码供您参考。

将文档生成变得更简单

昨天在文章中提到了生成文件的代码。

// 1件登録する
Document doc = new Document("name", "MongoDB")
                .append("type", "database")
                .append("count", 1)
                .append("info", new Document("x", 203).append("y", 102))
collection.insertOne(doc)

生成的文档(JSON)如下所示。

{
    "name" : "MongoDB", 
    "type" : "database", 
    "count" : 1,
    "info" : {
        "x" : 203,
        "y" : 102 
    }
}

哎呀!简单简单!
但是仔细一看,每次都要在每个字段后面加上append,这样太冗长了。
而且如果是嵌套的情况,还得再生成一个Document对象…
好的!有办法解决这个问题!

虽然话题听起来有点复杂,但实际上,Document类在构造函数中可以接受一个Map作为参数。
此外!在Groovy中,生成Map非常便捷。
现在,让我们看一下与上述代码等价的Groovy Map版本!

def doc2 = [
    "name": "MongoDB",
    "type": "database",
    "count": 1,
    "info": ["x": 203, "y": 102]
]
collection.insertOne(new Document(doc2))

这就是它!就只有这个!这段代码和一开始的一个追加代码完全相同!当使用最新的MongoDB官方Java驱动和Groovy功能结合时,代码会变得如此简洁!

将JSON(文本)保存

使用Groovy的GString,您可以轻松地将JSON表示为文本。
您无需声明任何特殊内容来使用GString。而且,如果您用三个双引号括起来,就可以轻松地编写换行符和转义字符。
另外,Document类作为静态方法提供了用于解析文本格式的JSON的parse方法,所以您可以将JSON文本传递给它,然后将其轻松保存到MongoDB中。

String jsonAsText = """
{
    "name": "Koji", 
    "age": 30, 
    "address":{
        "city": "Tokyo", 
        "country": "Japan"
    },
    "married": true,
    "favorites": ["Groovy", "Grails", "MongoDB"]
}
"""
collection.insertOne(Document.parse(jsonAsText))

通常的JSON被存储为文本(字符串)并赋值给jsonAsText变量,然后传递给Document.parse()方法。
通过这样做,就实现了使用Map生成Document实例的相同效果。

将JSON(对象)进行存储

现在,这到底是什么事情呢?
基本上,使用上述文本表示JSON的方法非常简单,因为可以在字符串中处理变量,所以没有什么问题。但是,在Groovy中还有一个名为JsonBuilder的类,可以简单地生成JSON对象。下次我们试着用JsonBuilder来做同样的事情。

// JsonBuilder経由
// Groovy上で、複雑なJSONを生成する場合、JsonBuilderがとっても便利。
def builder = new groovy.json.JsonBuilder()
builder {
        name 'Koji'
        age 30
        address(
            city: 'Tokyo',
            country: 'Japan'
        )
        married true
        favorites 'Groovy', 'Grails', 'MongoDB'
}
collection.insertOne(Document.parse(builder.toPrettyString()))

実行結果は上記の「JSON(テキスト)を保存する」と全く同じです。
JsonBuilderのインスタンスを生成して値をその中に記述していくだけです。
ちょっと書き方が独特で、通常JSONは “KEY: VALUE”の形式ですが、上記のJsonBuilderの書き方だとキーとバリューの間のコロンが必要なくなります。(が、addressの部分のようにそうでもない例外もあります。。。)
そしてDocument.parseにtoStringした値を渡すだけでOKです。
ちなみに、JsonBuilderにはbuilder.toPrettyStringというメソッドが用意されていて、buiderの値を綺麗に表示することが出来ます。

// println builder.toPrettyString()を実行した結果
{
    "name": "Koji",
    "age": 30,
    "address": {
        "city": "Tokyo",
        "country": "Japan"
    },
    "married": true,
    "favorites": [
        "Groovy",
        "Grails",
        "MongoDB"
    ]
}

编辑并保存JSON(文本)

现在,我们来看看关于“保存JSON(文本)”的应用部分。
JSON已经保存在String类型的变量jsonAsText中。
在这个状态下,如何才能修改值呢?
因为是文本,所以可以使用正则表达式进行替换。但是,这样做比较麻烦,不是吗?
如果使用Groovy,可以很容易地实现!
在Groovy中,有一个名为JsonSlurper的类,它可以将文本的JSON转换为类似Map的对象,利用它就可以实现。
现在让我们来看一下代码。

// JsonSlurper経由
// JsonSlurperを使うと、テキストで受け取ったJSONでも、通常のJSONオブジェクトのようにその中身を編集することができる
def slurper = new groovy.json.JsonSlurper().parseText(jsonAsText)
slurper.name = "JsonSlurper of Groovy!"
slurper.hoge = "piyo" // 存在しないフィールの追加もなんのその!
slurper.married = false
collection.insertOne(new Document(slurper))

JsonSlurperのインスタンスを生成して、parseTextメソッドにすでに存在しているテキスト形式のJSONを渡すだけです。
あとは通常のGroovyのMapのように扱えます!
そしてこのJsonSlurperインスタンスをnew Documentに渡してあげればちゃんとMongoDBに保存されます。

额外内容1(特定文档的更新)

在MongoDB中,updateOne和updateMany用于检索和更新目标文档。
那么,如果要在Groovy中处理相关文档的信息,并进一步更新该文档,应该怎么做呢?
实际上,我还没有完全理解…
暂时,可以使用以下代码检索文档,并将每个type字段的内容附加到相应的_id字段的值,进行更新。可能还有其他更好的方法,但这个暂时应该没有问题。

collection.find(eq("name", "MongoDB")).collect {
    ["_id":it._id, "newType": "NoSQL(ObjectId = ${it._id})"]
}.each {
    collection.updateOne(eq("_id", it._id), set("type", it.newType.toString()))
}

额外2(JsonBuilder的组合)

请问是什么意思呢?简单来说,就是在JsonBuilder实例内处理另一个JsonBuilder实例。
然而,有点特殊的是,另一个JsonBuilder在JsonBuilder内被使用时,必须通过.content来获取其值。
可能听起来有点难以理解。让我们来看看源代码吧!

def builder2 = new groovy.json.JsonBuilder()
builder2 {
    abc 'def'
    fromOtherJsonBuilder builder.content
}
println builder2.toPrettyString()
collection.insertOne(Document.parse(builder2.toPrettyString()))

用以下的代码将一个新的文档保存在MongoDB中:
“`
println builder2.toPrettyString()
“`

其中,builder2.toPrettyString()方法打印的JSON如下:

{
    "abc": "def",
    "fromOtherJsonBuilder": {
        "name": "Koji",
        "age": 30,
        "address": {
            "city": "Tokyo",
            "country": "Japan"
        },
        "married": true,
        "favorites": [
            "Groovy",
            "Grails",
            "MongoDB"
        ]
    }
}

没有什么特别困难的地方,这只是将原本存在的JsonBuilder对象用另一个JsonBuilder包装起来的形式而已。
通过查看fromOtherJsonBuilder builder.content,可以看出只需简单地从另一个JsonBuilder实例的.content中获取内容即可。
在像这样的例子中,将已经存在的JSON用另一个JSON包装起来,当然可以使用文本方式实现,但代码可能变得混乱不堪。
在这种情况下,JsonBuilder可以发挥作用。

概述

いかがだったでしょうか。
Groovyを使えば、MongoDB用の公式Java用ドライバを使って、さらに便利、シンプルにMongoDBを扱えることがわかったのではないでしょうか。
最後に、今回のコードの全体を記述して終わりにさせていただきます。
ありがとうございました。

明天是@h1romas4先生!

@Grab(group='org.mongodb', module='mongo-java-driver', version='3.1.1')

import com.mongodb.MongoClient
import com.mongodb.client.MongoDatabase
import com.mongodb.client.MongoCollection
import org.bson.Document
import static com.mongodb.client.model.Filters.*
import static com.mongodb.client.model.Sorts.*
import static com.mongodb.client.model.Updates.*
import com.mongodb.client.result.UpdateResult

// MongoDB本体に接続
MongoClient mongoClient = new MongoClient("localhost", 27017)
// 利用するデータベースに接続(データベース名はgroovy)
MongoDatabase db = mongoClient.getDatabase("groovy")
// 利用するコレクションに接続(コレクション名はtest)
MongoCollection<Document> collection = db.getCollection("test")

// DELETE ALL EXISTING DOCUMENTS
if (collection.count() > 0) {
    collection.deleteMany(new Document())
}

// 1件登録する
Document doc = new Document("name", "MongoDB")
                .append("type", "database")
                .append("count", 1)
                .append("info", new Document("x", 203).append("y", 102))
collection.insertOne(doc)

// 上の例と等価
def doc2 = [
    "name": "MongoDB",
    "type": "database",
    "count": 1,
    "info": ["x": 203, "y": 102]
]
collection.insertOne(new Document(doc2))

// テキストなJSONを保存する
String jsonAsText = """
{
    "name": "Koji", 
    "age": 30, 
    "address":{
        "city": "Tokyo", 
        "country": "Japan"
    },
    "married": true,
    "favorites": ["Groovy", "Grails", "MongoDB"]
}
"""
collection.insertOne(Document.parse(jsonAsText))

// JsonBuilder経由
// Groovy上で、複雑なJSONを生成する場合、JsonBuilderがとっても便利。
// ちょっと書き方が独特で、通常JSONは "KEY: VALUE"の形式だけど、間のコロンが必要なくなる。
def builder = new groovy.json.JsonBuilder()
builder {
        name 'Koji'
        age 30
        address(
            city: 'Tokyo',
            country: 'Japan',
        )
        married true
        favorites 'Groovy', 'Grails', 'MongoDB'
}
collection.insertOne(Document.parse(builder.toString()))


// JsonSlurper経由
// JsonSlurperを使うと、テキストで受け取ったJSONでも、通常のJSONオブジェクトのようにその中編みを編集することができる
def slurper = new groovy.json.JsonSlurper().parseText(jsonAsText)
slurper.name = "JsonSlurper of Groovy!"
slurper.hoge = "piyo" // 存在しないフィールの追加もなんのその!
slurper.married = false
collection.insertOne(new Document(slurper))
广告
将在 10 秒后关闭
bannerAds