MongoDB和Grails

所以最近,我需要存储从Web服务返回的非结构化JSON数据。 该网络服务正在返回来自世界各地的各种足球队。 在大多数足球队包含的数据中,有一部分足球运动员属于该队。 有些球队有12名球员,有些则有20名,有些甚至超过20名。球员拥有自己的属性,有些很容易预测,有些则不可能。 对于整个数据结构,我知道肯定会回来的唯一属性是团队的团队名称。 之后,它取决于每个团队。

{
   "teams": [{
       "teamname":"Kung fu pirates",
       "founded":1962,
       "players": [
          {"name": "Robbie Fowler", "age": 56},
          {"name": "Larry David", "age": 55}
          ...
        ]},
        { 
        "teamname":"Climate change observers",
        "founded":1942,
        "players": [
          {"name": "Jim Carrey", "age": 26},
          {"name": "Carl Craig", "age": 35}
          ...
        ]},
        ...
   ]

}

有几种不同的方法来存储此数据。 我决定去MongoDB。 主要原因:

  • 我想以与从Web服务获取的JSON响应尽可能接近的格式存储数据。 这意味着更少的代码,更少的错误,更少的麻烦。
  • 我想要的东西学习曲线很低,有很好的文档和良好的行业支持(stackoverflow线程,博客文章等)
  • 包含已记录的grails插件,出现脚步声并看起来像在维护的东西
  • 诸如文本词干等功能很不错。 一些支持本来会很好,但是并不需要缩短年龄。
  • 将支持良好的JSON搜索工具,索引等。

MongoDB勾选了所有框。 这就是我如何使其全部正常工作的方式。 按照Mongo的说明MongoDB Grails插件安装MongoDB之后,就该编写一些代码了。 现在这是整洁的部分,几乎没有任何代码。 我为团队创建了一个域对象。

class Team implements Serializable {

    static mapWith = "mongo"

    static constraints = {
    }

    static mapping = {
        teamname index: true
    }

    String teamname

    List players
    static embedded = ['players']
}

关于团队域对象:

  • 关于Team域对象的第一点是,我什至不需要创建它。 我之所以使用这种方法,是因为我愿意的话可以使用GORM风格的api,例如Team.find()
  • 玩家只是对象列表。 我没有费心创建一个Player对象。 我喜欢始终确保团队中的球员始终处于List数据结构中的想法,但是我认为不需要进一步键入任何内容。
  • 播放器被标记为嵌入式 。 这意味着团队和参与者都存储在单个非规范化数据结构中。 除其他事项外,这使您能够在单个数据库操作中检索和操作团队数据。
  • 我将团队名称标记为索引。
  • 我将域对象标记为:
    static mapWith = "mongo"

    这意味着,如果我还在我的GORM上使用了另一个持久性解决方案(postgres,MySQL等),我告诉GORM该Team域类仅适用于Mongo,请避免使用关系。 参见这里获取信息。
    注意:这很好地提醒了GORM是比休眠更高的抽象级别。 可能有一个不使用休眠模式但转到NoSQL存储区并且没有进入休眠模式的GORM对象。

您会注意到,在JSON中,存在尚未在Team类中显式声明的team属性(例如founded) 。 这就是Groovy和NoSQL彼此真正发挥作用的地方。 我们可以使用Groovy的某些Meta编程功能将属性动态添加到Team域对象。

private List importTeams(int page) {
    def rs = restClient.get("teams") // invoke web service
    List teams = rs.responseData.teams.collect {
         teamResponse ->
                Team team = new Team(teamname: teamResponse.teamname)
                team.save(); // Save is needed to dynamically add the attribute
                teamname.each {key, value ->
                    team["$key"] = value 
                }
                teamname.save(); // We need the second save to ensure the variants get saved.
                return teamname
        }
    log.info("importTeams(),teams=teams);
    teams
}

好的,所以我们的importTeams()方法的要点是:

  • 得到JSON响应后,我们在teams数组上运行了一个collect函数。 这将创建团队域对象。
  • 我们使用一些元编程将JSON团队结构中返回的任何属性动态添加到Team对象。 注意:我们必须先调用save()才能将Team域对象中声明的属性动态添加到Team域对象中。 我们还必须再次调用save(),以确保在Team域对象中声明的属性可以确保被保存。 这可能会在将来的MongoDB插件版本中发生变化,但这是我必须要做的工作(我使用的是MongoDB插件3.0.1版)

下一个是什么? 编写一些查询。 好的,这里有两个选择。 首先,得益于MongoDB插件,您可以将动态查找器和条件查询与GORM一起使用。 但是,我没有这样做。 为什么? 我想写的查询尽可能接近应该如何在Mongo中编写。 造成这种情况的原因有很多:

  • 在这里泄漏抽象是不可避免的。 迟早您将不得不编写一个查询,指出GORM不能很好地执行。 最好还是朝这个方向前进。
  • 我希望能够首先在Mongo控制台中运行查询,检查解释计划(如果需要),然后在代码中使用相同的查询。 如果我直接编写查询而不必担心GORM会做什么,则这样做更容易。

查询的一般格式为:

teams = Team.collection.find(queryMap) // where queryMap is a map of fields and the various values you are searching for.

好的,一些查询示例...

Team.collection.find(["teamname":"hicks"]) // Find a team name hicks
Team.collection.find(["teamname":"hicks", "players.name": "Robbie Fowler"] // As above but also has Robbie Fowler
Team.collection.find(["players.name": "Robbie Fowler"] // Any teams that has a Robbie Fowler
Team.collection.find(["teamname":"hicks", "players.name": "Robbie Fowler", {"players.$":1}]  // Returns matching player only
Team.collection.find(["teamname":"/ick/"]) // Match on the regular expression /ick/, i.e. any team that contains text ick.

还要别的吗? 当然可以。 在开发过程中,我想连接到我自己的机器上的Mongo实例,但在其他环境(CI,舞台,生产)中,我想连接到专用服务器上的Mongo机器。 为此,我将DataSource.groovy更新为:

environments {
    development {
        grails {
            mongo {
                host = "localhost"
                port = 27017
                username = "test"
                password = "test"
                databaseName = "mydb"
            }
        }
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }

    
    ci {
        println("In bamboo environment")
        grails {
            mongo {
                host = "10.157.192.99"
                port = 27017
                username = "shop"
                password = "shop"
                databaseName = "tony"
            }
        }
        dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
            url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
        }
    }
}

您会看到我已经配置了多个数据源(MongoDB和PostGres)。 我不主张同时使用MongoDB和关系数据库,只是指出这是可能的。 另一点是,MongoDB配置始终处于以下状态: grails {mongo {

好的,这是一个简单的介绍性帖子,我将尽快尝试发布更复杂的内容。 在下一次之前,请多保重。

翻译自: https://www.javacodegeeks.com/2014/06/mongodb-and-grails.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值