当前位置: 首页 > 知识库问答 >
问题:

MongoDB中的数组交集

戚泰
2023-03-14

好吧,这里有几件事。。我有两个集合:test和test1。这两个集合中的文档都有一个数组字段(分别是tags和tags1),其中包含一些标记。我需要找到这些标记的交叉点,如果单个标记匹配,还需要从集合test1获取整个文档。

> db.test.find();
{
    "_id" : ObjectId("5166c19b32d001b79b32c72a"),
    "tags" : [
            "a",
            "b",
            "c"
    ]
}          
> db.test1.find();
{
    "_id" : ObjectId("5166c1c532d001b79b32c72b"),
    "tags1" : [
            "a",
            "b",
            "x",
            "y"
    ]
}
> db.test.find().forEach(function(doc){db.test1.find({tags1:{$in:doc.tags}})});

令人惊讶的是,这并没有返回任何结果。但是,当我尝试使用单个文档时,它是有效的:

js prettyprint-override">> var doc = db.test.findOne();
> db.test1.find({tags1:{$in:doc.tags}});
{ "_id" : ObjectId("5166c1c532d001b79b32c72b"), "tags1" : [ "a", "b", "x", "y" ] }

但这是我需要的一部分。我也需要交集。所以我尝试了这个:

> db.test1.find({tags1:{$in:doc.tags}},{"tags1.$":1});
{ "_id" : ObjectId("5166c1c532d001b79b32c72b"), "tags1" : [ "a" ] }

但它只返回“a”,而“a”和“b”都在标记1中。位置运算符是否仅返回第一个匹配?此外,在中使用$也不会给我一个确切的交叉点。。如何获得交点(应返回“a”和“b”),而不管哪个数组与另一个数组进行比较

现在假设有一个操作员可以做到这一点。。

> db.test1.find({tags1:{$intersection:doc.tags}},{"tags1.$":1});
{ "_id" : ObjectId("5166c1c532d001b79b32c72b"), "tags1" : [ "a", "b" ] }

我的要求是,我需要整个tags1数组加上这个交集,在相同的查询中,如下所示:

> db.test1.find({tags1:{$intersection:doc.tags}},{"tags1":1, "tags1.$":1});
{ "_id" : ObjectId("5166c1c532d001b79b32c72b"), "tags1": [ "a", "b", "x", "y" ],
"tags1" : [ "a", "b" ] }

但这是一个无效的json。重命名key是可能的,还是只能通过聚合框架(并且跨不同的集合?)?我用$in尝试了上述查询。但它的行为好像完全忽略了"tags: 1"投影。

PS:我将有至少10k文档在test1和很少(

谢谢你的帮助!

共有3个答案

申屠弘图
2023-03-14

如果您想实时实现这一点,应该考虑远离服务器端Javascript,因为它只使用一个线程运行,速度应该很慢(单线程)(对于v2.4来说,这不再是事实,http://docs.mongodb.org/manual/core/server-side-javascript/)

位置运算符只返回第一个匹配/当前值。在不知道内部实现的情况下,如果文档已经被评估为匹配,从性能的角度来看,寻找进一步的匹配条件是没有意义的。所以我怀疑你能做到这一点。

我不知道您是否需要笛卡尔产品来进行搜索,但我会考虑将您的几个test-one文档标记合并成一个,然后在test1上搜索一些$,返回所有匹配的文档。在本地计算机上,可以有多个线程为文档生成交集。

根据您的test1和测试集合更改的频率,您正在执行此查询,您可能会预先计算此信息。这将允许轻松地对包含交集信息的字段进行查询。

该文档无效,因为您有两个字段名称标签1

郑胡媚
2023-03-14

Mongo没有任何固有的检索阵列交点的能力。如果确实需要使用特殊查询,请在客户端获取交叉点。

另一方面,考虑使用Map-Reduce并将其输出存储为集合。您可以在finize部分中增加返回的对象以添加交叉标签。Cron MR每隔几秒钟运行一次。您可以从客户端查询永久集合的好处。

利俊迈
2023-03-14

在较新版本中,您可以使用聚合来实现这一点。

db.test.aggregate(
    {
        $match: {
            tags1: {
                $in: doc.tags
            }
        }
    },
    {
        $project: {
            tags1: 1,
            intersection: {
                $setIntersection: [doc.tags, "$tags1"]
            }
        }
    }
);

如您所见,匹配部分与您最初的search()查询完全相同。project部分生成结果字段。在这种情况下,它从匹配的文档中选择tags1,并从输入和匹配的文档中创建交集

 类似资料:
  • 问题内容: 我有以下mongodb文件结构: 我已经能够使用$ elemMatch来更新操作中的字段,但是当我尝试对参数执行相同的操作(修改)时,它似乎不起作用。我想知道我应该尝试哪种其他方法,以便能够成功更新特定参数中的字段(通过其pid查找)。 我当前拥有但不起作用的更新代码如下所示: 问题答案: MongoDB 3.6及更高版本 MongoDB3.6及更高版本提供了一项新功能,该功能允许您使

  • 我在一个名为course的模式中有一个名为students的数我创建了一个路由,允许我使用学生的将学生添加到这个数组中,如下所示: 当我尝试用以下JSON体向我的endpoint发出PUT请求时: 谢谢!

  • 问题内容: 我在此站点上看到了此代码。它使用一种方法来对数组进行排序,其中偶数排在数组的前面,而奇数排在数组的后面。我想知道您是否可以做同样的事情,除了先显示奇数,然后再显示偶数?我试过了,但无济于事。我是Java编程的新手,我想测试递归。 } 输出是这样的: 问题答案: 好吧,如果你想单号是第一位的,取代任何与任何带:

  • 返回两个数组中都存在的元素列表。 根据数组 b 创建一个 Set 对象,然后在数组 a 上使用 Array.filter() 方法,只保留数组 b 中也包含的值。 const intersection = (a, b) => { const s = new Set(b); return a.filter(x => s.has(x)); }; intersection([1, 2, 3],

  • b)“Units”字段包含带有“period”字段的子文档(日期对象数组),其中给定的日期位于数组中的第一和第二元素之间。 数据结构如下所示: 我尝试使用.find()和.aggregate()的各种组合,例如在periol数组上使用$project和$filter,在unit._id上使用$elemmatch之后使用$elemmatch,但是没有用--我得到了诸如“不能在数组上使用$filter

  • 问题内容: 我在Spring中使用mongotemplate,我想知道如何自动原子地增加数组中的一个文档的值。想象我们有 我想要的是_id 341445从3到4的增量c 我一直在使用findAndModify,但是我不知道如何为数组中的嵌套文档创建它。 问候。 问题答案: 要更新数组字段中的元素,可以使用位置$运算符 例如,以下js将_id 341445的c从3递增到4: