查找一个字段与数组中另一个字段进行比较的文档

2023-10-02前端开发问题
2

本文介绍了查找一个字段与数组中另一个字段进行比较的文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

假设我有一组如下所示的文档:

<代码>{"_id" : ObjectId("5afa6df3a24cdb1652632ef5"),由...制作" : {_id":59232a1a41aa651ddff0939f"},所有者" : {_id":5abc4dc0f47f732c96d84aac"},acl":[{轮廓" : {_id":59232a1a41aa651ddff0939f"}},{轮廓" : {_id":5abc4dc0f47f732c96d84aac"}}]}

我想查找 createdBy._id != owner._id 的所有文档,以及 createdBy._id 出现在 中的条目之一的位置acl 数组.最终,我将要更新所有此类文档以将 owner._id 字段设置为等于 createdBy._id 字段.现在,我只是想弄清楚如何查询我想要更新的文档子集.

到目前为止,我想出了这个:

db.boards.find({$where: "this.createdBy._id != this.owner._id",$哪里:函数(){返回 this.acl.some(函数(e)=>{e.profile._id === this.createdBy._id}, 这);})

(我使用了 ES5 语法,以防 ES6 不行)

但是当我运行这个查询时,我得到了以下错误:

<块引用>

错误: 错误: { "ok" : 0, "errmsg" : "TypeError: e.profile is未定义 : _funcs2/<@:2:36 _funcs2@:2:12 ", "code" : 139 }

如何执行此查询/这里发生了什么?根据 docs 我读过.上面,e 应该是 acl 数组的一个元素,所以我希望它有一个字段 profile,但这似乎没有就是这样.

注意,我使用的是 Mongo 3.2,所以我不能使用 $expr,我已经看到一些资源表明这是一种可能性.

分辨率

事实证明,我对这个集合的架构做出了错误的假设.我遇到上述错误的原因是因为某些文档有一个 acl 数组,其中一个元素没有 profile 字段.下面的查询检查这种情况.它也有一个 $where,因为我最初编写它的方式(有两个)似乎最终给了我条件的 OR 而不是 AND.

db.boards.find({$哪里:函数(){返回 this.acl.some(函数(e)=>{e.profile !== 未定义 &&e.profile._id === this.createdBy._id &&this.createdBy._id != this.owner._id}, 这);})

解决方案

您仍然可以在此处将 aggregate() 与 MongoDB 3.2 一起使用,但只需使用 $redact 改为:

db.boards.aggregate([{ "$ 编辑": {"$cond": {如果": {$和":[{ "$ne": ["$createdBy._id", "$owner._id" ] },{ "$setIsSubset": [["$createdBy._id"], "$acl.profile._id"] }]},"然后": "$$KEEP",其他":$$PRUNE"}}}])

或使用 $where 对于 MongoDB 3.2 shell,您只需要保留 this 的范围副本,并且您的语法有点偏离:

db.boards.find({$哪里":函数(){变种自我=这个;返回(this.createdBy._id != this.owner._id)&&this.acl.some(函数(e){返回 e.profile._id === self.createdBy._id})}})

或者在 ES6 兼容的环境中:

db.boards.find({$哪里":函数(){返回(this.createdBy._id != this.owner._id)&&this.acl.some(e => e.profile._id === this.createdBy._id)}})

聚合是两者中性能最高的选项,应该总是比使用 JavaScript 评估更可取

对于它的价值,使用 $ 的新语法expr 将是:

db.boards.find({"$expr": {$和":[{ "$ne": ["$createdBy._id", "$owner._id" ] },{ "$in": ["$createdBy._id", "$acl.profile._id"] }]}})

使用 $in优先于 $setIsSubset 其中语法稍微短一些.

<小时><块引用>

注意 此处 JavaScript 比较有效的唯一原因是您错误地将 ObjectId 值存储为这些字段中的字符串".哪里有一个真实的"ObjectId 就像在 _id 字段中一样,比较需要从 valueOf() 中取字符串"比较顺序:

 返回 (this.createdBy._id.valueOf() != this.owner._id.valueOf())&&this.acl.some(e => e.profile._id.valueOf() === this.createdBy._id.valueOf())

<块引用>

没有它实际上是与 JavaScript 的对象比较",而 { a: 1 } === { a: 1 } 实际上是 false.因此,避免这种复杂性是另一个原因有本机运算符来代替.

Let's say I have a collection of documents that look like this:

{
    "_id" : ObjectId("5afa6df3a24cdb1652632ef5"),
    "createdBy" : {
        "_id" : "59232a1a41aa651ddff0939f"
    },
    "owner" : {
        "_id" : "5abc4dc0f47f732c96d84aac"
    },
    "acl" : [
        {
            "profile" : {
                "_id" : "59232a1a41aa651ddff0939f"
            }
        },
        {
            "profile" : {
                "_id" : "5abc4dc0f47f732c96d84aac"
            }
        }
    ]
}

I want to find all documents where createdBy._id != owner._id, AND where the createdBy._id appears in one of the entries in the acl array. Eventually, I will want to update all such documents to set the owner._id field to equal the createdBy._id field. For now, I'm just trying to figure out how to query the subset of documents I want to update.

So far, I have come up with this:

db.boards.find({
  $where: "this.createdBy._id != this.owner._id", 
  $where: function() {
    return this.acl.some(
      function(e) => {
        e.profile._id === this.createdBy._id
      }, this);
  }
)

(I have used ES5 syntax just in case ES6 isn't ok)

But when I run this query, I get the following error:

Error: error: { "ok" : 0, "errmsg" : "TypeError: e.profile is undefined : _funcs2/<@:2:36 _funcs2@:2:12 ", "code" : 139 }

How do I perform this query / what is going on here? I would have expected my query to work, based on the docs I've read. Above, e should be an element of the acl array, so I expect it to have a field profile, but that doesn't seem to be the case.

Note, I'm using Mongo 3.2, so I can't use $expr, which I've seen some resources suggest is a possibility.

Resolution

It turns out that I had made an incorrect assumption about the schema of this collection. The reason I was running into the above error is because some documents have an acl array with an element that doesn't have a profile field. The below query checks for this case. It also has a single $where, because the way I had written it originally (with two) seemed to end up giving me an OR of the conditions instead of an AND.

db.boards.find({
  $where: function() {
    return this.acl.some(
      function(e) => {
        e.profile !== undefined && e.profile._id === this.createdBy._id && this.createdBy._id != this.owner._id
      }, this);
  }
)

解决方案

You can still use aggregate() here with MongoDB 3.2, but just using $redact instead:

db.boards.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$and": [
          { "$ne": [ "$createdBy._id", "$owner._id" ] },
          { "$setIsSubset": [["$createdBy._id"], "$acl.profile._id"] }
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

Or with $where for the MongoDB 3.2 shell, you just need to keep a scoped copy of this, and your syntax was a bit off:

db.boards.find({
  "$where": function() {
    var self = this;
    return (this.createdBy._id != this.owner._id)
      && this.acl.some(function(e) {
        return e.profile._id === self.createdBy._id
     })
  }
})

Or in an ES6 compatible environment then:

db.boards.find({
  "$where": function() {
    return (this.createdBy._id != this.owner._id)
      && this.acl.some(e => e.profile._id === this.createdBy._id)
  }
})

The aggregate is the most performant option of the two and should always be preferable to using JavaScript evalulation

And for what it's worth, the newer syntax with $expr would be:

db.boards.find({
  "$expr": {
    "$and": [
      { "$ne": [ "$createdBy._id", "$owner._id" ] },
      { "$in": [ "$createdBy._id", "$acl.profile._id"] }
    ]
  }
})

Using $in in preference to $setIsSubset where the syntax is a little shorter.


NOTE The only reason the JavaScript comparison here works is because you have mistakenly stored ObjectId values as "strings" in those fields. Where there is a "real" ObjectId just like in the _id field, the comparison needs to take the "string" from valueOf() in order to compare:

    return (this.createdBy._id.valueOf() != this.owner._id.valueOf())
      && this.acl.some(e => e.profile._id.valueOf() === this.createdBy._id.valueOf())

Without that it's actually an "Object Comparison" with JavaScript and { a: 1 } === { a: 1 } is actually false. So avoiding that complexity is another reason there are native operators for this instead.

这篇关于查找一个字段与数组中另一个字段进行比较的文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

The End

相关推荐

js删除数组中指定元素的5种方法
在JavaScript中,我们有多种方法可以删除数组中的指定元素。以下给出了5种常见的方法并提供了相应的代码示例: 1.使用splice()方法: let array = [0, 1, 2, 3, 4, 5];let index = array.indexOf(2);if (index -1) { array.splice(index, 1);}// array = [0,...
2024-11-22 前端开发问题
182

JavaScript小数运算出现多位的解决办法
在开发JS过程中,会经常遇到两个小数相运算的情况,但是运算结果却与预期不同,调试一下发现计算结果竟然有那么长一串尾巴。如下图所示: 产生原因: JavaScript对小数运算会先转成二进制,运算完毕再转回十进制,过程中会有丢失,不过不是所有的小数间运算会...
2024-10-18 前端开发问题
301

JavaScript(js)文件字符串中丢失"\"斜线的解决方法
问题描述: 在javascript中引用js代码,然后导致反斜杠丢失,发现字符串中的所有\信息丢失。比如在js中引用input type=text onkeyup=value=value.replace(/[^\d]/g,) ,结果导致正则表达式中的\丢失。 问题原因: 该字符串含有\,javascript对字符串进行了转...
2024-10-17 前端开发问题
437

layui中table列表 增加属性 edit="date",不生效怎么办?
如果你想在 layui 的 table 列表中增加 edit=date 属性但不生效,可能是以下问题导致的: 1. 缺少日期组件的初始化 如果想在表格中使用日期组件,需要在页面中引入 layui 的日期组件,并初始化: script type="text/javascript" src="/layui/layui.js"/scrip...
2024-06-11 前端开发问题
455

Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript
Rails/Javascript: How to inject rails variables into (very) simple javascript(Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript)...
2024-04-20 前端开发问题
5

CoffeeScript 总是以匿名函数返回
CoffeeScript always returns in anonymous function(CoffeeScript 总是以匿名函数返回)...
2024-04-20 前端开发问题
13