Mongodb查询投射中的$elemMatch

本文研究查询过程中,定义数组返回结果的另外一个操作符$elemMatch。

定义

投射中elemMatch与操作符号一样,都是返回数组中第一个符合查询条件的数据。

但两个操作命令也有差异。使用符号时,用户只能通过查询条件来过滤数组元素。而使用elemMatch时,用户可以显示的定义更多的数组过滤条件。同时$elemMatch也支持文档数组中多个字段的查询条件定义。

字段顺序

在投射中,无论用户定义返回多少个字段,使用elemMatch和操作符号时, 4.4以后版本的mongodb都会将符合查询条件的数组结果,置于所有字段的后面。

向player集合插入一条数据

复制代码
db.players.insertOne({
    name: "player1",
    games: [
        { game: "abc", score: 8},
        { game: "xyz", score: 5}
        ],
    joined: new Date("2020-01-01"),
    lastLogin: new Date("2020-05-01")
})

使用$elemMatch构建查询语句,查找出score大于5的数据。其中指定返回字段games, joined, lastLogin

复制代码
db.players.find(
    {},
    {
        games: {$elemMatch: {"score": {$gt: 5}}},
        joined: 1, 
        lastLogin: 1
    })

查询结果中, games字段排列到了joined和lastLogin后。而在4.2及以前的mongodb版本中,games字段会按照用户查询投射中定义的字段顺序返回。

复制代码
{
	"_id" : ObjectId("65b594f1374038b32213a3e5"),
	"joined" : ISODate("2020-01-01T08:00:00.000+08:00"),
	"lastLogin" : ISODate("2020-05-01T08:00:00.000+08:00"),
	"games" : [
		{
			"game" : "abc",
			"score" : 8
		}
	]
}

使用限制

  • mongodb 视图中,不支持使用$elemMatch查询。
  • elemMatch中不能使用text查询表达式。

应用举例

构建测试集合

向schools集合中,插入带有数组students的4条数据

复制代码
db.schools.insertMany([
    {
     _id: 1,
     zipcode: "63109",
     students: [
                  { name: "john", school: 102, age: 10 },
                  { name: "jess", school: 102, age: 11 },
                  { name: "jeff", school: 108, age: 15 }
               ]
    },
    {
     _id: 2,
     zipcode: "63110",
     students: [
                  { name: "ajax", school: 100, age: 7 },
                  { name: "achilles", school: 100, age: 8 },
               ]
    },
    {
     _id: 3,
     zipcode: "63109",
     students: [
                  { name: "ajax", school: 100, age: 7 },
                  { name: "achilles", school: 100, age: 8 },
               ]
    },
    {
     _id: 4,
     zipcode: "63109",
     students: [
                  { name: "barney", school: 102, age: 7 },
                  { name: "ruth", school: 102, age: 16 },
               ]
    }
])

单字段查询

查询出zipcode是63109的数据,在返回结果中,显示第一个school是102的学生数据。

复制代码
db.schools.find(
    {zipcode: "63109"},
    {students: {$elemMatch: { school: 102}}}
)

返回结果

复制代码
/* 1 */
{
	"_id" : 1,
	"students" : [
		{
			"name" : "john",
			"school" : 102,
			"age" : 10
		}
	]
},

/* 2 */
{
	"_id" : 3
},

/* 3 */
{
	"_id" : 4,
	"students" : [
		{
			"name" : "barney",
			"school" : 102,
			"age" : 7
		}
	]
}

多字段查询

构建查询语句,返回zipcode是63109的数据。要求结果中返回第一个字段school是102,并且age大于10的数据。

复制代码
db.schools.find(
    {zipcode: "63109"},
    {students: {$elemMatch: { school: 102, age: {$gt: 10}}}}
)

返回结果

复制代码
/* 1 */
{
	"_id" : 1,
	"students" : [
		{
			"name" : "jess",
			"school" : 102,
			"age" : 11
		}
	]
},

/* 2 */
{
	"_id" : 3
},

/* 3 */
{
	"_id" : 4,
	"students" : [
		{
			"name" : "ruth",
			"school" : 102,
			"age" : 16
		}
	]
}
相关推荐
HAWK eoni6 分钟前
Mysql 驱动程序
数据库·mysql
二哈赛车手18 分钟前
新人笔记---实现简易版的rag的bm25检索(利用ES),以及RAG上传时的ES与向量数据库双写
java·数据库·笔记·spring·elasticsearch·ai
何中应28 分钟前
CentOS 7安装、卸载MySQL数据库(二)
数据库·mysql·centos
KmSH8umpK38 分钟前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第六篇
数据库·redis·分布式
梁萌1 小时前
mysql使用事件做日志表数据转移
数据库·mysql
lThE ANDE1 小时前
MySQL中的TRUNCATE TABLE命令
数据库·mysql
kexnjdcncnxjs1 小时前
Redis如何记录每一次写操作_开启AOF持久化机制实现命令级追加记录
jvm·数据库·python
逸Y 仙X2 小时前
文章十九: ElasticSearch Full Text 全文本查询
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
STER labo2 小时前
mysql配置环境变量——(‘mysql‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件解决办法)
数据库·mysql·adb
微软技术分享2 小时前
本地部署千问 2.5-1.5B-GGUF + LangChain 封装学习
数据库·学习·langchain