这是我必须制作应用程序的所有代码。所以我能够从csv文件导入数据/记录,或者从localhost:3000处的应用程序手动插入,它将被插入到数据库中。从那里我将能够从这里查询。错误在于底部的server.js。批量和平均值似乎都没有执行。
server.js,包括批量(1000data以上)和平均查询(air_temperature)
var express = require('express');
var app = express();
var mongojs = require('mongojs');
var db = mongojs('meibanlist', ['meibanlist']);
var bodyParser = require('body-parser');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());
app.get('/meibanlist', function (req, res) {
console.log('I received a GET request');
db.meibanlist.find(function (err, docs) {
console.log(docs);
res.json(docs);
});
});
app.post('/meibanlist', function (req, res) {
console.log(req.body);
db.meibanlist.insert(req.body, function(err, doc) {
res.json(doc);
});
});
app.delete('/meibanlist/:id', function (req, res) {
var id = req.params.id;
console.log(id);
db.meibanlist.remove({_id: mongojs.ObjectId(id)}, function (err, doc) {
res.json(doc);
});
});
app.get('/meibanlist/:id', function (req, res) {
var id = req.params.id;
console.log(id);
db.meibanlist.findOne({_id: mongojs.ObjectId(id)}, function (err, doc) {
res.json(doc);
});
});
app.put('/meibanlist/:id', function (req, res) {
var id = req.params.id;
console.log(req.body.machine_unit);
db.meibanlist.findAndModify({
query: {_id: mongojs.ObjectId(id)},
update: {$set: {machine_unit: req.body.machine_unit, air_temperature: req.body.air_temperature, water_temperature: req.body.water_temperature, heat_temperature: req.body.heat_temperature, room_temperature: req.body.room_temperature, date: req.body.date, time: req.body.time}},
new: true}, function (err, doc) {
res.json(doc);
}
);
});
var cursor = db.meibanlist.find({"air_temperature": { "$exists": true, "$type": 2 }}),
bulkUpdateOps = [];
cursor.forEach(function(doc){
var newTemp = parseInt(doc.air_temperature, 10);
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "air_temperature": newTemp } }
}
});
if (bulkUpdateOps.length === 500) {
db.meibanlist.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.meibanlist.bulkWrite(bulkUpdateOps); }
db.meibanlist.aggregate([
{
"$group": {
"_id": null,
"averageAirTemperature": { "$avg": "$air_temperature" }
}
}
], function(err, results){
if (err || !results) console.log ("record not found");
else console.log(results[0]["averageAirTemperature"]);
});
app.listen(3000);
console.log("Server running on port 3000");
的index.html
<!DOCTYPE>
<html ng-app="myApp">
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css">
<title>Meiban App</title>
</head>
<body>
<div class="container" ng-controller="AppCtrl">
<h1>Meiban App</h1>
<table class="table">
<thead>
<tr>
<th>Machine unit</th>
<th>Air Temperature</th>
<th>Water Temperature</th>
<th>Heat Temperature</th>
<th>Room Temperature</th>
<th>Date</th>
<th>Time</th>
<th>Action</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td><input class="form-control" ng-model="contact.machine_unit"></td>
<td><input class="form-control" ng-model="contact.air_temperature"></td>
<td><input class="form-control" ng-model="contact.water_temperature"></td>
<td><input class="form-control" ng-model="contact.heat_temperature"></td>
<td><input class="form-control" ng-model="contact.room_temperature"></td>
<td><input class="form-control" ng-model="contact.date"></td>
<td><input class="form-control" ng-model="contact.time"></td>
<td><button class="btn btn-primary" ng-click="addCollection()">Add Collection</button></td>
<td><button class="btn btn-info" ng-click="update()">Update</button> <button class="btn btn-info" ng-click="deselect()">Clear</button></td>
</tr>
<tr ng-repeat="contact in collection">
<td>{{contact.machine_unit}}</td>
<td>{{contact.air_temperature}}</td>
<td>{{contact.water_temperature}}</td>
<td>{{contact.heat_temperature}}</td>
<td>{{contact.room_temperature}}</td>
<td>{{contact.date}}</td>
<td>{{contact.time}}</td>
<td><button class="btn btn-danger" ng-click="remove(contact._id)">Remove</button></td>
<td><button class="btn btn-warning" ng-click="edit(contact._id)">Edit</button></td>
</tr>
</tbody>
</table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
<script src="controller/controller.js"></script>
</body>
</html>
controller.js
var myApp = angular.module('myApp', []);
myApp.controller('AppCtrl', ['$scope', '$http', function($scope, $http) {
console.log("Hello World from controller");
var refresh = function() {
$http.get('/meibanlist').success(function(response) {
console.log("I got the data I requested");
$scope.meibanlist = response;
$scope.contact = "";
});
};
refresh();
$scope.addCollection = function() {
console.log($scope.contact);
$http.post('/meibanlist', $scope.contact).success(function(response) {
console.log(response);
refresh();
});
};
$scope.remove = function(id) {
console.log(id);
$http.delete('/meibanlist/' + id).success(function(response) {
refresh();
});
};
$scope.edit = function(id) {
console.log(id);
$http.get('/meibanlist/' + id).success(function(response) {
$scope.contact = response;
});
};
$scope.update = function() {
console.log($scope.contact._id);
$http.put('/meibanlist/' + $scope.contact._id, $scope.contact).success(function(response) {
refresh();
})
};
$scope.deselect = function() {
$scope.contact = "";
}
}]);
答案 0 :(得分:1)
正如文档所指出的, $avg
运算符可以在两个管道步骤中运行, $project
和 {{3} } 阶段。我相信您需要在 $group
管道中使用 $avg
累加器,因为您需要所有价格的平均值。
在 $group
阶段使用时, $group
会返回将指定表达式应用到的所有数值的集体平均值按_id
字段标注的密钥共享同一组的一组文档中的每个文档。
_id
字段是必填字段;但是,由于您要计算所有输入文档的累计平均值,因此您可以指定_id
null
的值:
db.database.aggregate([
{
"$group": {
"_id": null,
"Average": { "$avg": "$price" }
}
}
], function(err, results){
if (err !results) console.log ("record not found");
else console.log(results[0]["Average"]);
});
整理评论中的信息以及您问题的后续更新,您遇到了麻烦,因为您的值不是数字,因此 $avg
无法正常工作。
您需要使用 $avg
方法将字符串值转换为数字值。这里的概念是update()
,对于游标中的每个文档,使用 loop through your collection with a cursor 使用 $set
。
假设您的集合不是那么庞大,上面的直觉可以使用游标的 parseInt()
方法来实现,以迭代它并更新集合中符合特定条件的每个文档。
以下mongo shell演示强调了针对小型数据集的这种方法:
mongo shell
db.meibanlist.find({"air_temperature": { "$exists": true, "$type": 2 }})
.snapshot()
.forEach(function(doc){
var newTemp = parseInt(doc.air_temperature, 10);
db.meibanlist.updateOne(
{ "_id": doc._id },
{ "$set": { "air_temperature": newTemp } }
);
});
现在,为了提高性能,特别是在处理大型集合时,请利用 forEach()
API批量更新集合。
与上述操作相比,这是非常有效的,因为使用批量API,您将批量发送操作到服务器(例如,批量大小为500),这会让您更好 性能,因为您不会将每个请求发送到服务器,而是每500个请求中只发送一次,从而使您的更新更有效,更快捷。
以下示例演示如何使用MongoDB版本>= 2.6
和< 3.2
中提供的 Bulk()
API。
mongo shell
var bulkUpdateOps = db.meibanlist.initializeUnOrderedBulkOp(),
counter = 0;
db.meibanlist.find({"air_temperature": { "$exists": true, "$type": 2 }})
.snapshot()
.forEach(function(doc){
var newTemp = parseInt(doc.air_temperature, 10);
bulkUpdateOps.find({ "_id": doc._id })
.update({ "$set": { "air_temperature": newTemp } })
counter++; // increment counter for batch limit
if (counter % 500 === 0) {
// execute the bulk update operation in batches of 1000
bulkUpdateOps.execute();
// Re-initialize the bulk update operations object
bulkUpdateOps = db.meibanlist.initializeUnOrderedBulkOp();
}
})
// Clean up remaining operation in the queue
if (counter % 500 !== 0) { bulkUpdateOps.execute(); }
下一个示例适用于自Bulk()
deprecated API以来的MongoDB版本3.2及更高版本,并使用 {{3}提供了一套更新的api } 强>
它使用与上面相同的游标,但使用相同的 Bulk()
游标方法创建具有批量操作的数组,以将每个批量写入文档推送到数组。因为写命令可以接受不超过1000次的操作,
您需要将操作分组以进行最多1000次操作,并在循环达到1000次迭代时重新初始化该数组。如果您的收藏很大,上面的计数器变量可以有效地管理您的批量更新。它允许您批量更新操作,并以500的批量将写入发送到服务器,这样可以提供更好的性能,因为您不会向服务器发送每个请求,每500个请求中只发送一次。
对于批量操作,MongoDB对每个批处理施加了1000个操作的默认内部限制,因此在对批量大小有一定控制而不是让MongoDB强加默认值的情况下,选择500个文档是好的,即对于大型操作在>的大小> 1000份文件。
var cursor = db.meibanlist.find({"air_temperature": { "$exists": true, "$type": 2 }}),
bulkUpdateOps = [];
cursor.forEach(function(doc){
var newTemp = parseInt(doc.air_temperature, 10);
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "air_temperature": newTemp } }
}
});
if (bulkUpdateOps.length === 500) {
db.meibanlist.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.meibanlist.bulkWrite(bulkUpdateOps); }
更新集合后,您可以在aggregate()
函数中愉快地应用 bulkWrite()
运算符。以下内容将返回所有合并文件的平均值air_temperature
:
db.meibanlist.aggregate([
{
"$group": {
"_id": null,
"averageAirTemperature": { "$avg": "$air_temperature" }
}
}
], function(err, results){
if (err !results) console.log ("record not found");
else console.log(results[0]["averageAirTemperature"]);
});
<强>更新强>
以上代码适用于mongo shell。对于mongojs版本,将操作封装在可以在需要时调用的函数中。例如,您可以将批量更新逻辑放在其自己的函数bulkUpdate中:
function bulkUpdate(collection, callback)
var ops = [];
collection.find({
"air_temperature": { "$exists": true, "$type": 2 }
}, function (err, docs) {
docs.forEach(function(doc){
ops.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": {
"air_temperature": parseInt(doc.air_temperature, 10),
"water_temperature": parseInt(doc.water_temperature, 10),
"heat_temperature": parseInt(doc.heat_temperature, 10),
"room_temperature": parseInt(doc.room_temperature, 10)
}
}
}
});
if (ops.length === 500) {
collection.bulkWrite(bulkUpdateOps, function(err, result){
if (err) callback(err);
callback(null, result);
});
ops = [];
}
});
if (ops.length > 0) {
collection.bulkWrite(ops, function(err, result){
callback(null, result);
});
}
});
}
以及获得平均温度的逻辑:
function getAverageTemps(collection, callback) {
collection.aggregate([
{
"$group": {
"_id": null,
"averageAirTemperature": { "$avg": "$air_temperature" },
"averageWaterTemperature": { "$avg": "$water_temperature" },
"averageHeatTemperature": { "$avg": "$heat_temperature" },
"averageRoomTemperature": { "$avg": "$room_temperature" }
}
}
], function(err, results){
if (err || !results) callback(err);
else callback(null, results);
});
}
然后您可以按如下方式调用,例如,您可以在API中放置一个端点来检索平均临时值:
app.get('/meibanlist/averagetemps', function (req, res) {
getAverageTemps(db.meibanlist, function (err, temps) {
if (err || !temps) console.log ("record not found");
else res.json(temps);
});
});