0

我有以下文件:

{
  "_id": "doc1"
  "binds": {
    "subject": {
      "Test1": ["something"]
    },
    "object": {
      "Test2": ["something"]
    }
  },
},
{
  "_id": "doc2"
  "binds": {
    "subject": {
      "Test1": ["something"]
    },
    "object": {
      "Test3": ["something"]
    }
  },
}

我需要一个 Mango 选择器来检索文档,其中绑定的任何字段(主题、对象等)都有一个对象,其键等于作为参数传递的数组中的任何值。即,if keys of binds contains any values of some array it should returns that document

例如,考虑["Test2"]我的选择器应该检索的数组,doc1因为它binds["subject"]["Test1"]存在;数组["Test1"]应该检索doc1anddoc2并且数组["Test2", "Test3"]也应该检索doc1and doc2

仅供参考,我正在使用带有nano lib 的 Node.js 来访问 CouchDB API。

4

1 回答 1

1

我提供这个答案是因为改变文档“模式”并不总是一种选择。

对于给定的文档结构,这不能以任何合理的方式使用 Mango 完成。是的,它可以做到,但只有在采用非常脆弱和低效的做法时。

Mango 没有提供查询文档以获取动态属性的有效方法;它确实支持在属性值中搜索,例如数组1

使用最坏的做法,此选择器将找到具有绑定属性subjectobject具有名为的Test2属性的文档Test3

{
   "selector": {
      "$or": [
         {
            "binds.subject.Test2": {
               "$exists": true
            }
         },
         {
            "binds.object.Test2": {
               "$exists": true
            }
         },
         {
            "binds.subject.Test3": {
               "$exists": true
            }
         },
         {
            "binds.object.Test3": {
               "$exists": true
            }
         }
      ]
   }
}

问题

  1. 查询的属性名称不同,因此无法利用 Mango 索引(Test37 有人吗?)
  2. 因为 (1)每次查询都会发生一次全索引扫描( )_all_docs
  3. 需要以编程方式生成$or子句
  4. 需要了解要查询的属性名称集(Test37 有人吗?)

给定的文档结构是 Mango 索引和查询的显示停止器。

这就是 map/reduce 的亮点

考虑一个带有地图功能的视图

function (doc) {
  for(var prop in doc.binds) {
    if(doc.binds.hasOwnProperty(prop)) {
      // prop = subject, object, foo, bar, etc
      var obj = doc.binds[prop];
      for(var objProp in obj) {
        if(obj.hasOwnProperty(objProp)) {
        // objProp = Test1, Test2, Test37, Fubar, etc
          emit(objProp,prop)
        }
      }
    }
  }
}

binds因此,map 函数为具有两个嵌套属性的属性的任何文档创建一个视图binds.subject.Test1,例如binds.foo.bar.

鉴于问题中的两个文档,这将是基本视图索引

ID 钥匙 价值
文档1 测试1 主题
文档2 测试1 主题
文档1 测试2 目的
文档2 测试3 目的

由于视图查询提供了keys参数,因此此查询将使用 JSON 提供您的特定解决方案

{
 include_docs: true,
 reduce: false,
 keys: ["Test2","Test3"]
}

使用 cUrl 查询该索引

$ curl -G http://{查看端点} -d 'include_docs=false' -d 'reduce=false' -d 'keys=["Test2","Test3"]'

会回来

{
  "total_rows": 4,
  "offset": 2,
  "rows": [
    {
      "id": "doc1",
      "key": "Test2",
      "value": "object"
    },
    {
      "id": "doc2",
      "key": "Test3",
      "value": "object"
    }
  ]
}

当然,还有一些选项可以通过利用排序规则和复杂的键来扩展这种视图的形式和功能,并且还有方便的reduce功能。

我看过评论说 Mango 非常适合 CouchDB 的新手,因为它在创建索引和查询选项方面“轻松”,如果对于经验更丰富的人来说,它的 map/reduce 也是如此。我相信这样的评论是善意的,但却被误导了;芒果很诱人,但也有缺陷1。视图确实需要相当多的思考,但是,嘿,无论如何我们都应该这样做。

1) $elemMatch例如需要内存扫描,这可能非常昂贵。

于 2021-03-22T16:05:02.260 回答