2013-07-05 50 views
12

Tôi đang sử dụng khuôn khổ MongoDB tập hợp và làm một số tính toán như hình dưới đâylàm tròn đến 2 chữ số thập phân sử dụng MongoDB hợp khuôn khổ

db.RptAgg.aggregate( 
{ $group : 
{ _id : {Region:"$RegionTxt",Mth:"$Month"},   
    ActSls:{$sum:"$ActSls"}, 
    PlnSls:{$sum:"$PlnSls"} 
} 
}, 
{ $project : 
{ 
    ActSls:1, 
    PlnSls:1, 
    ActToPln:{$cond:[{ $ne: ["$PlnSls", 0] },{$multiply:[{$divide: ['$ActSls', '$PlnSls']},100]},0]} 
    } 

} 

); 

Tôi đang cố gắng tìm ra cách tốt nhất và đơn giản nhất để làm tròn kết quả của tôi là những gì đến 2 chữ số thập phân. Sau đây là kết quả của tôi

{ 
    "result" : [ 
      { 
        "_id" : { 
          "Region" : "East", 
          "Mth" : 201301 
        }, 
        "ActSls" : 72, 
        "PlnSls" : 102, 
        "ActToPln" : 70.58823529411765 
      } 
    ], 
    "ok" : 1 

}

Tôi muốn "ActToPln" để hiển thị 70,59 thay vì "ActToPln": 70,58823529411765, trong các kết quả từ khuôn khổ aggegation riêng của mình. Tôi muốn tránh làm tròn trong đơn đăng ký của tôi

Bạn có thể vui lòng trợ giúp như vậy không.

Sau đây là tập dữ liệu tôi đã sử dụng.

{ 
    "_id" : ObjectId("51d67ef69557c507cb172572"), 
    "RegionTxt" : "East", 
    "Month" : 201301, 
    "Date" : "2013-01-01", 
    "ActSls" : 31, 
    "PlnSls" : 51 
} 
{ 
    "_id" : ObjectId("51d67ef69557c507cb172573"), 
    "RegionTxt" : "East", 
    "Month" : 201301, 
    "Date" : "2013-01-02", 
    "ActSls" : 41, 
    "PlnSls" : 51 
} 

Xin cảm ơn trước. Nandu

+0

bạn nên cung cấp một số ví dụ hay dữ liệu của bạn và đơn giản hóa câu hỏi của bạn –

+0

Tôi đã cập nhật câu hỏi và cũng cung cấp tập dữ liệu tôi đã sử dụng. Cảm ơn amezhenin. – user2552537

+4

Tại sao không làm điều đó trên máy khách? Không có cách tự nhiên để làm điều này trong khung công tác tổng hợp. Bạn sẽ cần phải sử dụng bản đồ giảm để thực hiện một chức năng làm tròn. – WiredPrairie

Trả lời

2

Không có toán tử tròn nào trong phiên bản hiện tại của Khung tổng hợp. Bạn có thể thử đoạn mã này:

> db.a.save({x:1.23456789}) 
> db.a.save({x:9.87654321}) 
> db.a.aggregate([{$project:{y:{$subtract:['$x',{$mod:['$x', 0.01]}]}}}]) 
{ 
    "result" : [ 
     { 
      "_id" : ObjectId("51d72eab32549f94da161448"), 
      "y" : 1.23 
     }, 
     { 
      "_id" : ObjectId("51d72ebe32549f94da161449"), 
      "y" : 9.870000000000001 
     } 
    ], 
    "ok" : 1 
} 

nhưng như bạn thấy, giải pháp này không hoạt động tốt vì vấn đề chính xác. Cách dễ nhất trong trường hợp này là làm theo lời khuyên của @wiredprairie và thực hiện round giây trong ứng dụng của bạn.

+0

Cảm ơn bạn đã phản hồi điểm @amezhenin. – user2552537

13

Không có toán tử $round nhưng bạn có thể thực hiện việc này trong khung tổng hợp - thực hiện theo thứ tự cụ thể thường sẽ tránh các vấn đề về độ chính xác của dấu phẩy động.

> db.a.save({x:1.23456789}) 
> db.a.save({x:9.87654321}) 
> db.a.aggregate([{$project:{ _id:0, 
     y:{$divide:[ 
       {$subtract:[ 
         {$multiply:['$x',100]}, 
         {$mod:[{$multiply:['$x',100]}, 1]} 
       ]}, 
       100]} 
}}]) 
{ "y" : 1.23 } 
{ "y" : 9.87 } 

Với tuyến ống hiện hữu trong vấn đề này, thay thế:

{$multiply:[{$divide: ['$ActSls', '$PlnSls']},100]} 

với

{$divide:[ 
    {$subtract:[ 
      {$multiply:[ 
      {$divide: ['$ActSls','$PlnSls']}, 
      10000 
      ]}, 
      {$mod:[ 
      {$multiply:[{$divide: ['$ActSls','$PlnSls']}, 10000 ]}, 
      1]} 
      ]}, 
    100 
]} 

Với mẫu của bạn điểm dữ liệu này là kết quả:

{ "ActSls" : 31, "PlnSls" : 51, "ActToPln" : 60.78 } 
{ "ActSls" : 41, "PlnSls" : 51, "ActToPln" : 80.39 } 
{ "ActSls" : 72, "PlnSls" : 102, "ActToPln" : 70.58 } 
+2

lưu ý rằng kỹ thuật này * cắt ngắn * kết quả thành hai chữ số thập phân. Nếu bạn muốn thực sự * tròn *, bạn nên thêm 49 trước khi phân chia cuối cùng 100. –

+0

Asya, bạn có thể vui lòng cho biết biến/hằng số nào trong khối mã db.a.save đầu tiên của bạn ({x: 1.23456789}). ... thực sự làm tròn số. Tôi đang nói như chúng ta làm trong C#, ví dụ Math.Round (123.234, 2). Trong đó 2 là số chữ số thập phân số sẽ được làm tròn thành. Ngoài ra, bạn có thể vui lòng sửa đổi mã trên theo nhận xét được đề cập ở trên (thêm 49 trước khi phân chia cuối cùng là 100). –

+0

Trong các bước: cho x là một số, tôi nhân x với 100 và trừ từ mod đó x * 100,1 (là phần phân số sau phép nhân).Điều đó khiến tôi với số nguyên là 100x của những gì tôi muốn giữ vì vậy sau đó tôi chia nó bằng 100. 1.5478 * 100 => 154.78 mod của chia cho 1 là .78 vì vậy sau khi trừ tôi có 154 mà tôi chia cho 100. 1.54 trái . Đối với số thập phân khác nhau sau. sử dụng bội số khác nhau của 10 thay vì 100. –

1

mongo-round hoạt động tốt đẹp. Cách sạch nhất tôi đã tìm thấy.

Nói số là 3.3333333

var round = require('mongo-round'); 

db.myCollection.aggregate([ 
    { $project: { 
     roundAmount: round('$amount', 2) // it will become 3.33 
    } } 
]); 
0
{$divide:[ 
      {$cond: { if: { $gte: [ {$mod:[{$multiply:['$dollarAmount',100]}, 1]}, 0.5 ] }, then: {$add: [{$subtract:[ 
        {$multiply:['$dollarAmount',100]}, 
        {$mod:[{$multiply:['$dollarAmount',100]}, 1]} 
      ]} 
       ,1]}, else: {$subtract:[ 
        {$multiply:['$dollarAmount',100]}, 
        {$mod:[{$multiply:['$dollarAmount',100]}, 1]} 
      ]} }} 
      , 
      100]} 

hy vọng những ai có thể giúp đỡ trong việc làm tròn số.

1

Giải pháp này viên đạn một cách chính xác lên hoặc xuống để 2dp:

"rounded" : { 
    $subtract:[ 
    {$add:['$absolute',0.0049999999999999999]}, 
    {$mod:[{$add:['$absolute',0.0049999999999999999]}, 0.01]} 
    ] 
} 

Ví dụ nó vòng 1,2499 lên đến 1,25, nhưng 1,2501 xuống đến 1,25.

Ghi chú:

  1. giải pháp này được dựa trên các ví dụ được đưa ra tại http://www.kamsky.org/stupid-tricks-with-mongodb/rounding-numbers-in-aggregation-framework
  2. Nó giải quyết vấn đề trong câu trả lời Asya Kamsky của, nó chỉ sẽ cắt cụt và không round up/down correctly; ngay cả sau khi thay đổi được đề xuất trong các nhận xét.
  3. Số lượng dấu 9 trong hệ số bổ sung là lớn, để chứa số đầu vào chính xác cao. Tùy thuộc vào độ chính xác của các số được làm tròn, yếu tố bổ sung có thể cần phải được thực hiện chính xác hơn thế này.
0

Tôi không biết tại sao, nhưng tất cả các câu trả lời (tại trang này) cho tôi 12.34 cho 12.345. Vì vậy, tôi đã viết giai đoạn dự án của riêng mình:

x = 12.345 

{'$project': { 
    y: {'$divide': [{'$trunc': {'$add': [{'$multiply': ['$x', 100]}, 0.5]}}, 100]}, 
}}, 

Nó cung cấp 12.35.

Dưới đây là số học đơn giản, không có thủ đoạn:

  1. 12,345 * 100 = 1234,5 # Bước này được chúng tôi làm tròn số các mục: 100 = 10^2 (hai dấu hiệu sau dấu chấm). Bước này sẽ được cân bằng trở lại bước 4.
  2. 1234,5 + 0,5 = 1235,0 # Ở đây tôi nhận được của tôi round half up
  3. truncate (1235,0) = 1235 # Đơn giản chỉ cần giảm một phần phân đoạn
  4. 1235/100 = 12,35

Tuy nhiên, nó không hoạt động chính xác cho âm bản (đó là đủ cho tổng hợp của tôi). Đối với cả hai trường hợp (tích cực và tiêu cực), bạn nên sử dụng nó với abs:

{'$project': { 
    z: {'$multiply': [ 
     {'$divide': ['$x', {'$abs': '$x'}]}, 
     {'$divide': [{'$trunc': {'$add': [{'$multiply': [{'$abs': '$x'}, 100]}, 0.5]}}, 100]} 
    ]}, 
}} 

Ở đây tôi nhận được dấu hiệu số của, quấn số ban đầu bởi abs và sau đó nhân lên dấu bằng cách làm tròn đầu ra.

0
rounded:{'$multiply': [{ "$cond": [{ "$gte": [ "$x", 0 ] }, 1,-1 ]},{'$divide': [{'$trunc': {'$add': [{'$multiply': [{'$abs': '$x'}, {$pow:[10,2]}]}, 0.5]}}, {$pow:[10,2]}]}]} 

giải pháp của egvo rất tuyệt nhưng phân chia bằng không nếu nó bằng 0. Để tránh $ cond có thể được sử dụng để phát hiện dấu hiệu

(Thay x với field_name và số 2 với số thập phân mong muốn)

Các vấn đề liên quan