MongoDB:如何计算文档中键的数量?

37

假设有一个文档:

{

a: 1,
b: 1,
c: 2,
 ....
z: 2
}

我该如何计算这个文档中键的数量?

谢谢


6
为什么这个帖子会被踩?这是一个相当合理的问题。给你点赞。 - Remon van Vliet
7个回答

22

如果使用MongoDB 3.6及更新版本,可以通过聚合框架实现。在聚合管道中使用$objectToArray操作符将文档转换为数组。返回的数组包含原始文档中每个字段/值对应的元素。返回数组中的每个元素都是一个包含两个字段kv的文档。

通过$$ROOT系统变量,可以引用代表在聚合管道阶段中正在处理的顶层文档的根文档。

获取数组后,您可以利用$addFields管道步骤创建一个包含计数的字段,而实际计数是通过使用$size操作符派生的。

所有这些都可以在单个管道中完成,将表达式嵌套如下:

db.collection.aggregate([
    { "$addFields": {
        "count": {
            "$size": { 
                "$objectToArray": "$$ROOT"
            }
        }
    } }     
])

输出示例

{
    "_id" : ObjectId("5a7cd94520a31e44e0e7e282"),
    "a" : 1.0,
    "b" : 1.0,
    "c" : 2.0,
    "z" : 2.0,
    "count" : 5
}

为了排除 _id 字段,你可以使用 $filter 操作符,如下所示:

db.collection.aggregate([
    {
        "$addFields": {
            "count": {
                "$size": { 
                    "$filter": {
                        "input": { "$objectToArray": "$$ROOT" },
                        "as": "el",
                        "cond": { "$ne": [ "$$el.k", "_id" ] }
                    }
                }
            }
        }
    }     
])

或者按照 0zkr PM 的建议,在开始时添加一个$project管道步骤:

db.collection.aggregate([
    { "$project": { "_id": 0 } },
    { "$addFields": {
        "count": {
            "$size": { 
                "$objectToArray": "$$ROOT"
            }
        }
    } }     
])

1
在聚合管道中,只需添加一个 $project,以取代 filter - 0zkr PM

11

没有专门的指令可以完成这个功能。请获取该文档并自行统计密钥。


1
@daydreamer:现在已经有一个命令可以解决这个问题了,请选择其他答案。 - Sergio Tulentsev

8
在MongoDB(以及大多数NoSQL解决方案)中,如果您希望之后进行查询(例如“键的数量> 12”),通常最好预先计算这些值,因此您可能应该考虑添加一个新字段“keyCount”,每次添加新键时都会增加它。

3
如果您正在Mongo控制台中,可以编写JavaScript来完成此操作。
doc = db.coll.findOne({}); nKeys =0; for( k in doc){nKeys ++;} print(nKeys);

这仍然被视为“mongo之外”。

2
你也可以直接使用 nKeys = Object.keys(doc).length; - Nic Cottrell

1
const MongoClient = new require("mongodb").MongoClient(
  "mongodb://localhost:27017",
  {
    useNewUrlParser: true,
    useUnifiedTopology: true
  }
);
(async () => {
  const connection = await MongoClient.connect();
  const dbStuff = await connection
    .db("db")
    .collection("weedmaps.com/brands")
    .find({})
    .toArray();  // <- Chuck all it into an Array
  for (let thing of dbStuff) {
    console.log(Object.keys(thing).length);
  }
  return await connection.close();
})();

1

Sergio是正确的,你必须在Mongo之外完成它。

你可以像这样做:

var count = 0;
for(k in obj) {count++;}
print(count);

1
如果您正在使用类似于mongoose.Document文件,则可以尝试在将其转换为对象后计算doc内的所有键,因为之前,doc仅具有普通属性:
Object.keys(document); // returns [ '$__', 'isNew', 'errors', '_doc', '$locals' ]
Object.keys(document).length; // returns ALWAYS 5

因此,尝试将其转换为对象,然后将其传递给 Object.keys

console.dir(
    Object.keys(document.toObject()) // Returns ['prop1', 'prop2', 'prop3']
);

并显示键数。
console.log(
    Object.keys(document.toObject().length)
); // Returns 3

并且要快乐!!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接