mongodb 按照条件查询,如何把这条查询出来的记录里的字段如email的值提取出来,保存为String类型

mongodb 按照条件查询,如何把这条查询出来的记录里的字段如email的值提取出来,保存为String类型,第1张

String email = "";

if(myDoccontainsField("email")){

Object email_ = myDocget("email");

if(email_ instanceof String){

email = (String)email_ ;

}else {

email = email_toString();

}

}

不管通过何种方式,数据库给你的结果只会是:

[{name: 'bob'},

{name: 'ahn'},

{name: 'abc'}]

如果是在shell下面,可以用JS脚本进行转换:

var cursor = dbcollfind({}, {_id: 0, name: 1});var result = cursormap(function(doc) { return docname;

});

这里用到cursormap方法。在不同的驱动中应该都有不同的实现。但这部分工作实际上不是数据库为你完成的,而是驱动在app端做的转换。数据库是紧要资源,在不影响性能的前提下应该尽可能把消耗资源的行为都放到应用端。因为相比数据库,应用的水平扩展要容易并且成本更低。

在工作中有时遇到这么一种场景 找出那些字段A和字段B相等的数据

刚开始只能想到自己联表查自己,后面研究了一下,发现了更简单的方法,分享出来

假设我们有以下测试数据

是一张 暗恋表 ,有人喜欢别人,有人自恋

我们现在想要 找出那些自恋的人

lookup语法

根据语法和常规思路,我们写下了如下查询

( $unwind 是用来拍平数据结构的,因为联表之后,嵌套字段是一个列表)

查询之后发现 结果为空

嗯?我们把 match 删了看一下结果是啥

可以看到,联表的确是生效了,但是我们要找的是 自恋 , 而不是 有人爱 ,

联表之后还差一步,就是找到 name 等于 love_yourselfname 的记录

但是,等等,貌似又回到了最初的问题: 找到字段相等的数据

所以,联表也遇到同样的问题,也就是联表并没有解决这个问题,所以此路不通

然后在官方文档的 query 里面找啊找,发现了 expr 的 *** 作,例子很有意思

然后我想,我把 gt 换成 eq 行不行呢

把查询语句换一下

结果如下

bingo! 可以了

这个问题暂时解决了,但是平时工作中,经常遇到 ObjectId 和 String 互相匹配的问题

那么在这种场景下,语句如何写呢?

我们准备好测试数据

值一样的,标记为了同一个颜色

我们先来试一下,思路不变,能不能查出来(语句有变化,字段换成了 _id )

很遗憾,不能

此时还是在 expr 的文档里看到了这么一个例子

很明显, $expr 的 参数列表,参数类型可以是 转换函数,不一定就需要是老老实实的字段, 如图中就是用了 $cond 作为条件函数来转换字段,

那么我把 ObjectId 转为 String 类型的是不是就可以了呢

来试一下以下的查询语句

结果如下

OK,这个场景也解决了

建立SimpleTestjava,完成简单的mongoDB数据库 *** 作 Mongo mongo = new Mongo(); 这样就创建了一个MongoDB的数据库连接对象,它默认连接到当前机器的localhost地址,端口是27017。 DB db = mongogetDB(“test”); 这样就获得了一个test的数据库,如果mongoDB中没有创建这个数据库也是可以正常运行的。如果你读过上一篇文章就知道,mongoDB可以在没有创建这个数据库的情况下,完成数据的添加 *** 作。当添加的时候,没有这个库,mongoDB会自动创建当前数据库。 得到了db,下一步我们要获取一个“聚集集合DBCollection”,通过db对象的getCollection方法来完成。 DBCollection users = dbgetCollection("users"); 这样就获得了一个DBCollection,它相当于我们数据库的“表”。 查询所有数据 DBCursor cur = usersfind(); while (curhasNext()) { Systemoutprintln(curnext()); } 完整源码 package comhootest; import javanetUnknownHostException; import commongodbDB; import commongodbDBCollection; import commongodbDBCursor; import commongodbMongo; import commongodbMongoException; impor 建立SimpleTestjava,完成简单的mongoDB数据库 *** 作

Mongo mongo = new Mongo();

这样就创建了一个MongoDB的数据库连接对象,它默认连接到当前机器的localhost地址,端口是27017。

DB db = mongogetDB(“test”);

这样就获得了一个test的数据库,如果mongoDB中没有创建这个数据库也是可以正常运行的。如果你读过上一篇文章就知道,mongoDB可以在没有创建这个数据库的情况下,完成数据的添加 *** 作。当添加的时候,没有这个库,mongoDB会自动创建当前数据库。

得到了db,下一步我们要获取一个“聚集集合DBCollection”,通过db对象的getCollection方法来完成。

DBCollection users = dbgetCollection("users");

这样就获得了一个DBCollection,它相当于我们数据库的“表”。

查询所有数据

DBCursor cur = usersfind();

while (curhasNext()) {

Systemoutprintln(curnext());

}

完整源码

package comhootest;

import javanetUnknownHostException;

import commongodbDB;

import commongodbDBCollection;

import commongodbDBCursor;

import commongodbMongo;

import commongodbMongoException;

import commongodbutilJSON;

/

<b>function:</b>MongoDB 简单示例

@author hoojo

@createDate 2011-5-24 下午02:42:29

@file SimpleTestjava

@package comhootest

@project MongoDB

@blog >

在MongoDB中,文档是对数据的抽象,它被使用在Client端和Server端的交互中。所有的Client端(各种语言的Driver)都会使用这种抽象,它的表现形式就是我们常说的BSON(Binary JSON )。

BSON是一个轻量级的二进制数据格式。

MongoDB能够使用BSON,并将BSON作为数据的存储存放在磁盘中。

当Client端要将写入文档,使用查询等等 *** 作时,需要将文档编码为BSON格式,然后再发送给Server端。同样,Server端的返回结果也是编码为BSON格式再放回给Client端的。

如果我们在日常 *** 作中,将部分数据存储在了MongoDB中,但是有需求要求我们将存储进去的文档数据,按照一定的条件进行查询过滤,得到想要的结果便于二次利用,那么我们就可以尝试使用MongoDB的聚合框架。

前面我们在学习文档查询的过程中,也介绍过一些查询的 *** 作符,其中就有一部分是简单的查询聚合函数,例如 count 、 distinct 、 group 等,如果是简单的数据分析过滤,完全可以使用这些自带的聚合函数以及查询的 *** 作符来完成文档的过滤查询 *** 作

如果我们遇到了一些数据需要跨多个文本或者统计等 *** 作,这个时候可能文档自身也较为复杂,查询 *** 作符已经无法满足的时候,这个时候就需要使用MongoDB的聚合查询框架了。

使用聚合框架可以对集合中的文档进行变换和组合查询,基本上我们使用的时候,都是使用多个构件创建一个管道,用于对一连串的文档进行处理。这里的构件包括 筛选(filter) 、 投射(projecting) 、 分组(grouping) 、 排序(sorting) 、 限制(limiting) 以及 跳过(skipping)

MongoDB中需要使用聚合 *** 作,一般使用 aggregate 函数来完成多个聚合之间的连接,aggregate() 方法的基本语法格式如下 :

现在假设我们有个集合articles,里面存储了文章的集合,大致如下:

但这时我们需要查询出来每一个作者写的文章数量,需要使用aggregate()计算 ,大致如下:

输出的结果为:

通过这个简单的案例我们就能输出想要的数据和属性名,大概分析一下刚刚的聚合查询语句, by_user字段进行分组,代表每个用户一条数据,而num_tutorial则是定义了数值类型计算的结果字段,$sum则是计算总和,相当于每个用户出现一次,都会+1,最终计算出来的总和通过num_tutorial字段进行输出

注:如果管道没有给出预期的结果,就需要进行调试 *** 作,调试的时候,可以尝试先给一个管道 *** 作符的条件,如果这个时候查询出来的结果是我们想要的,那么我们需要再去指定第二个管道 *** 作符,依次 *** 作,最后就会定位到出了问题的 *** 作符

前面我们提到聚合查询会使用管道 *** 作符,而每一个 *** 作符就会接受一连串的文档,对这些文档进行一些类型转换,最后将转换以后的文档结果传递给下一个管道 *** 作符来执行后续的 *** 作,如果当前是最后一个管道 *** 作符,那么则会显示给用户最后的文档数据。不同的管道 *** 作符是可以按照顺序组合在一起使用,并且可以被重复执行多次,例如我们可以先使用$match然后再去、 match *** 作。

match管道 *** 作符可以使用$gt、$lt、$in等 *** 作符,进行过滤,不过需要注意的是不能在$match管道 *** 作符中使用空间地理 *** 作符。

在实际使用的过程中,尽可能的将 match *** 作符以后,再去投射或者执行分组 *** 作的话,是可以利用索引的。

相比较一般的查询 *** 作而言,使用管道 *** 作,尤其是其中的投射 *** 作更加强大。我们可以在查询文档结束以后利用 $project *** 作符从文档中进行字段的提取,甚至于我们可以重命名字段,将部分字段映射成我们想要展示出去的字段,也可以对一部分字段进行一些有意义的处理。需要注意的是, $project *** 作符可以传入两个参数,第一个是需要处理的属性名称,第二个则是0或者1,如果传入1,则代表当前的属性是需要显示出来的,如果是0或者不写,默认都是代表这个字段不需要显示出来

当然第二个参数也可以是一个表达式或者查询条件,满足当前表达式的数据也可以进行显示,接下来我们先准备一点数据:

接下来,我们来查询,条件是item字段为abc,quantity要大于5,并且我们只要item和price字段的结果,其他都排除掉:

可以看到结果为:

如果我们想要在原基础上改变某个字段的名称,例如将item改为item_code,可以利用$来完成,如下:

可以看到我们指定的名称item_code,而这个别名对应的字段item使用$作为前缀标记,代表将item字段映射为item_code,可以看到结果:

我们在投影的时候,除了可以将某个字段映射成其他字段以外,还可以针对某个字段进行一些简单的运算,最常见的就是 四则运算 ,即

加法( subtract )、乘法( divide )、求模( $mod ) ,

除此之外,还支持对字段进行 关系运算 (大小比较( " eq" )、大于( " gte" )、小于( " lte" )、不等于( " ifNull" ) )、

逻辑运算 (与( " or" )、非 ( " concat" )、截取( " toLower" ) )等

我们基于上面的需求,假设每一个价格是按照元为单位,现在要求输出W为单位,那么我们就需要对price进行除法运算,如下:

除此之外,我们也可以将计算完毕的price改名为priceW,即:

可以看到输出的结果为:

这时有一个需求,要求我们返回数据的同时还要yyyy-MM-dd格式的时间字符串,这个时候我们就需要对date字段进行时间函数和字符串混合处理了,如下:

这里需要注意的一点是, year:" substr函数将date字段的结果截取成字符串即可实现拼接

group的_id上,代表按照当前字段进行分组,例如,我们这里根据item进行分组:

在我们针对某个字段进行分组以后,我们可以针对每个分组进行一些 *** 作符的使用,常见的例如: $sum 、 $avg 、 $min 、 $max 、 $first 、 $last 。

$avg *** 作符用来返回每一个分组内的平均值

现在我们基于前面item的分组,我们想要算出来每个组内的平均价格是多少,如下:

$min 和 $max *** 作符用于返回分组内最大的值和最小的值

除了平均值以外,我们现在将最贵的和最便宜的价格也要列出来,这个时候就可以使用这两个 *** 作符了,如下:

$first 、 $last 则是可以获取当前分组中第一个或者最后一个的某个字段的结果,如下:

除此之外,我们还可以在分组的时候使用数组 *** 作符,例如 $addToSet 可以判断,当前数组如果不包含某个条件,就添加到当前数组中, $push 则不管元素是否存在,都直接添加到数组中

注意:大部分管道 *** 作符都是流式处理的,只要有新的文档进入,就可以对新的文档进行处理,但是 $group 代表必须收到全部文档以后才可以进行分组 *** 作,才会将结果传递给后续的管道 *** 作符,这就意味着,如果当前mongo是存在分片的,会先在每个分片上执行完毕以后,再把结果传递mongos进行统一的分组,剩下的管道 *** 作符也不会在每个分片,而是mongos上执行了

如果我们现在遇到一些文档比较复杂,比如存在内嵌文档的存在,某个属性里面嵌套了一个数组,但是我们需要对内嵌的数组文档进行分析过滤等查询处理,这个时候就可以使用 $unwind *** 作符将每一个文档中的嵌套数组文件拆分为一个个独立的文档便于进行后续的处理,例如我们需要将之前的set集合中关于请求的url以及ip的信息拆分出来,原始的格式如下:

我们可以使用命令进行拆分,如下:

结果为:

可以看到数据则是按照每一条信息的方式展示出来了,方便后续的计算以及输出,但是需要注意的一点是,这种方式,如果该文档中没有拆分的字段,或者是空数组,默认会直接排除,如果我们需要空数组等也输出计算出来,则可以指定 preserveNullAndEmptyArrays 参数,设置为true,则代表空数组或者不存在的文档也要拆分输出出来,即:

我们可以在管道查询的过程中,按照某个属性值或者多个属性的结果进行顺序排序,排序的方式与普通查询 *** 作符中的sort *** 作符表现一致,与其他管道 *** 作符一样,可以在任何阶段使用,但是,需要注意的一点是,建议在管道 *** 作符第一阶段进行排序,因为此时的排序是可以触发索引的,如果在后续阶段进行排序,会消耗大量内存,并且耗时会很久,尤其是在有 $group 的情况下,如果放在 $group *** 作符后面,会发现等到的时间很久,不仅仅是无法触发索引的问题,还和 $group *** 作符是等待所有数据完毕才会触发的特性有关,因此需要格外注意。

结果如下,按照我们想要的结果进行了排序:

limit,只返回前两条数据,如下:

结果如下:

除了 skip,与之前的查询 *** 作符作用也是一样的,用于在已经查询完毕的结果集中跳过前N条数据以后进行返回,我们将$skip加在刚刚的查询后面,如下:

这个时候可以看到返回的结果为空,什么结果都没有了,这是因为前一步管道已经限制了仅仅返回2条,而接着我们又跳过了前两条文档,因此返回的结果为空,我们将顺序调换一下,看看:

可以看到结果如下,与刚才的结果无异:

管道查询 *** 作符有很多,除了上面学习的常用的部分,还有几十个,需要了解全部的可以参考官网:

>

以上就是关于mongodb 按照条件查询,如何把这条查询出来的记录里的字段如email的值提取出来,保存为String类型全部的内容,包括:mongodb 按照条件查询,如何把这条查询出来的记录里的字段如email的值提取出来,保存为String类型、如何用mongodb获取某个字段集合、MongoDB 查询技巧(1) - 字段相等等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9784588.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-01
下一篇2023-05-01

发表评论

登录后才能评论

评论列表(0条)

    保存