有没有办法在mongodb中获取对象字段的长度?

时间:2015-11-29 07:27:19

标签: mongodb mapreduce mongodb-query aggregation-framework

例如,如果我在MongoDB中有以下对象:

{
    {
        "name": "pencil",
        "purchase_record": {
            "1":"$900",
            "2":"$1000",
            "3":"$1100",
            "4":"$1200"
        }
    },
    {
        "name": "pen",
        "purchase_record": {
            "1":"$1000",
            "2":"$1200",
            "3":"$900",
            "4":"$1100",
            "5":"$1100"
        }
    }
}

有没有办法获得" purchase_record"对于每条记录?

2 个答案:

答案 0 :(得分:1)

@JohnnyHK指出,您应该考虑更改文档结构,使purchase_record成为一个数组。执行此操作的最佳方法是使用"bulk"操作。

var bulk = db.xx.initializeUnorderedBulkOp();
var count = 0;
db.xx.find().forEach(function(doc) { 
    var purchase_record = doc.purchase_record; 
    var newRecord = []; 
    for(var key in purchase_record) {
        if(Object.prototype.hasOwnProperty.call(purchase_record, key))
            newRecord.push({'units': key, 'price': purchase_record[key]});
    } 
    bulk.find( { '_id': doc._id } ).updateOne( {
        '$set': { 'purchase_record': newRecord } } ); 
    count++; 
    if(count % 300 === 0) { 
        // Execute per 300 operations
        bulk.execute();
        bulk = db.xx.initializeUnorderedBulkOp(); 
    } 
})

// Clean up queues
if (count > 0) bulk.execute();

完成此操作后,您的文档如下所示:

{
        "_id" : ObjectId("565aad654036f6520c25a9bb"),
        "name" : "pencil",
        "purchase_record" : [
                {
                        "units" : "1",
                        "price" : "$900"
                },
                {
                        "units" : "2",
                        "price" : "$1000"
                },
                {
                        "units" : "3",
                        "price" : "$1100"
                },
                {
                        "units" : "4",
                        "price" : "$1200"
                }
        ]
}
{
        "_id" : ObjectId("565aad654036f6520c25a9bc"),
        "name" : "pen",
        "purchase_record" : [
                {
                        "units" : "1",
                        "price" : "$1000"
                },
                {
                        "units" : "2",
                        "price" : "$1200"
                },
                {
                        "units" : "3",
                        "price" : "$900"
                },
                {
                        "units" : "4",
                        "price" : "$1100"
                },
                {
                        "units" : "5",
                        "price" : "$1100"
                }
        ]
}

现在,您可以使用.aggregate()方法访问汇总管道$project您的文档并返回“purchase_record”$size

db.xx.aggregate([
    { '$project': { 
        '_id': 0, 
        'name': 1, 
        'size_purchase_record': { '$size': '$purchase_record' } 
    }} 
])

返回:

{ "name" : "pencil", "size_purchase_record" : 4 }
{ "name" : "pen", "size_purchase_record" : 5 }

您始终可以使用以下内容将“purchase_record”字段添加到结果中:'purchase_record': 1

使用文档当前结构,您可以使用mapReduce方法执行此操作:

var map = function() { 
    var records = []; 
    for(var key in this.purchase_record) {
        if(Object.prototype.hasOwnProperty.call(this.purchase_record, key)) 
            records.push(key); 
    } 
    var recordsLen = records.length; 
    emit(this.name, recordsLen);
};
var reduce = function(key, values) { return values; };
db.xx.mapReduce(map, reduce, { out: { inline: 1 } } );

返回:

{
        "results" : [
                {
                        "_id" : "pen",
                        "value" : 5
                },
                {
                        "_id" : "pencil",
                        "value" : 4
                }
        ],
        "timeMillis" : 1,
        "counts" : {
                "input" : 2,
                "emit" : 2,
                "reduce" : 0,
                "output" : 2
        },
        "ok" : 1
}

.map方法效率不高,因为它是客户端。

db.xx.find().map(function(doc) { 
    return {
        'name': doc.name, 
        'purchase_record_len': Object.keys(doc.purchase_record).length
    }; 
})

哪个收益率:

[
        {
                "name" : "pencil",
                "purchase_record_len" : 4
        },
        {
                "name" : "pen",
                "purchase_record_len" : 5
        }
]

答案 1 :(得分:1)

这是一个古老的问题,但是$objectToArray的答案非常简单,可从MongoDB 3.4.4版获得

你可以做;

db.collection.aggregate([
  {
    $project: {
      _id: 0,
      name: 1,
      purchaseCount: {
        $size: {
          "$objectToArray": "$purchase_record"
        }
      }
    }
  }
])

哪个将给出purchase_record中的字段数,结果将是;

[
  {
    "name": "pencil",
    "purchaseCount": 4
  },
  {
    "name": "pen",
    "purchaseCount": 5
  }
]

mongoplayground上互动查看