You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MongoDB的Ruby服务端自定义函数执行替代方案咨询

替代MongoDB $eval计算客户对象大小的可行方案

Hey there! I totally get the pain of $eval needing full database permissions—definitely not something you want in production. Let's break down your questions and go through practical alternatives:

1. Can you call saved system.js functions without $eval?

Short answer: No, not directly. MongoDB's server-side JavaScript functions stored in system.js are designed to be invoked either via $eval, or within MapReduce/aggregation stages (with limitations). Since $eval is off the table due to permissions, relying on system.js isn't a viable path here. Let's look at better options.

Option 1: Calculate Document Size in Ruby (Application Layer)

This is the simplest and most permission-friendly approach. The MongoDB Ruby driver lets you serialize documents to BSON and calculate their byte size directly in your app:

# Initialize your client
client = Mongo::Client.new(['your-mongo-host:27017'], database: 'your_database')
customers_collection = client[:customers]

# Iterate through customers and compute size
customers_collection.find.each do |customer_doc|
  bson_size = customer_doc.to_bson.length
  puts "Customer #{customer_doc['_id']} document size: #{bson_size} bytes"
end

No special MongoDB permissions needed here—just standard read access to the customers collection. You can also easily tweak this to exclude specific fields from the size calculation if needed.

Option 2: Use Aggregation Framework with $bsonSize (MongoDB 4.4+)

If you prefer doing the calculation on the database side (better for large datasets), use the $bsonSize operator in an aggregation pipeline. This requires only read permissions on the collection, no full database access:

size_calculation_pipeline = [
  {
    '$addFields' => {
      'document_size_bytes' => { '$bsonSize' => '$$ROOT' }
    }
  }
]

# Run the aggregation and process results
customers_collection.aggregate(size_calculation_pipeline).each do |doc|
  puts "Customer #{doc['_id']} size: #{doc['document_size_bytes']} bytes"
end

This is efficient and leverages MongoDB's native capabilities—way better than $eval or MapReduce for modern MongoDB versions.

Option 3: MapReduce (For Older MongoDB Versions)

If you're stuck on a MongoDB version pre-4.4 (no $bsonSize), MapReduce can work. You can use your saved system.js function here without $eval:
First, save the size-calculation function to system.js via the Ruby driver:

client[:system.js].insert_one({
  _id: 'getDocSize',
  value: BSON::Code.new('function(doc) { return Object.bsonsize(doc); }')
})

Then run the MapReduce job:

map_func = BSON::Code.new('function() { emit(this._id, getDocSize(this)); }')
reduce_func = BSON::Code.new('function(key, values) { return values[0]; }')

results = customers_collection.map_reduce(map_func, reduce_func).to_a
results.each do |result|
  puts "Customer #{result['_id']} size: #{result['value']} bytes"
end

Note: MapReduce is deprecated in newer MongoDB versions, so use this only if you can't upgrade to 4.4+.

Final Recommendation

Go with Option 1 if you want maximum control and minimal database dependencies, or Option 2 if you need database-side processing for large datasets. Both avoid the permission issues of $eval entirely.

内容的提问来源于stack exchange,提问作者Michal Molhanec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:03:27