mongodb内嵌数组如何实现过滤?
发布于 8 年前 作者 redhu 8886 次浏览 来自 问答

请教下, 如何实现下面的查询 { title : ‘xxx’, arr : [{del:1, name:1}, {del:0, name:2},{del:0, name:3}] } -> { title : ‘xxx’, arr: [{del:0, name:2},{del:0, name:3}] } 针对内嵌数组的过滤, 我目前找不到好的方案, 哪位帮看下, 不胜感激.

=================================================== 谢谢各位的建议, 这两天通过查找文章/和网友交流也更新了我对nosql设计的见解. 我之前一直认为在mongodb的集合里引入了其他集合的句柄(_id)的设计是不"正宗"的, 看来还是too simple.推荐好文:http://www.jianshu.com/p/bb0caddff60a

目前的解决方案是: mongodb的聚集框架, 可以比较好的解决我这个问题. 原理是先利用unwind把数据展开, 过滤完以后在汇总. 如果大家有更好的方案, 还请不吝赐教.

12 回复
db.connection.find( { title : "xxx" },{ title:1,arr: { $elemMatch: { name: {$ne:1} } } } )

@holyselina 采用$elemMatch的方式,只能获取到数组里第一个,不能获取到所有.

摸不着头脑。 数据库查找针对的都是某条记录/某个对象,返回结果也是记录/对象实体。你的查询要求更像是业务层面的filter,就好比正则里的子查询返回匹配到的字符一样;或者是mysql里 like “%abc%” 要求返回结果里的字段只含有abc。 真想在数据库层面做,是不是可以考虑独立arr出来。

@xltank 是可以独立出来,把arr里面的内容作为另外一个集合去存储. 但是个人觉得这样的设计更接近于关系型的设计.mongodb的find命令里第一个参数是过滤条件,可以视为从海量数据把符合预期的数据捞回来, 第二个参数是用来处理单个数据的,所以我认为我的需求应该在第二个参数里可以实现,不过好像没有.

不太明白这个是分享帖还是问答帖,对于数组中的过滤最优方案是使用聚合的unwind将数组拆开,然后在后续的stage中添加过滤条件(注1),以此来达到筛选出所需数据的目的; 注1:该模式存储设计时要非常小心,由于使用unwind是讲arr中每个item拆分出来,然后拼接剩下所有的冗余字段组成一条新的doc,所以对于该doc要求除arr外不能有其他太大的arr,否则,unwind后很容易会超出16M限制;其次,对于整条doc,要考虑是采用one-few 还是 one-many,因为数组中的数据过大也会影响最后聚合查询的速度,无要求限制,更是致命的;综上。根据具体业务需求,设计出适合自己的存储结构,后续查询才不会吃力;

@haozxuan 问答帖, 谢谢解惑. 横线后是我后来查到的解决方案. 谢谢关于one-few one-many的建议.

无论是aggregation 还是 map-reduce都不应该是常规的查询方式。collection结构及相互关系的设计需要考虑业务需求,如果本帖描述的需求比较常规,还是应该考虑对collection做调整

喝喜酒几十块

@xltank 是的, 一开始数据库设计我走了极端. 可以通过数据库设计优化避免这种情况

这个有select的

@redhu 先不考虑聚集,我不太明白为什么只能获取第一个,你要过滤内嵌的数组,相当于映射,映射过滤.$elemMatch会过滤返回符合表达式条件的元素.映射过滤在where条件之后.光看你之前的代码块,也有可能我理解错你的需求

使用聚合管道

回到顶部