Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 为什么在$save()期间,它会在mongoDB中生成一个带有字符串id的新条目?_Node.js_Mongodb_Angularjs_Angularjs Resource_Mean Stack - Fatal编程技术网

Node.js 为什么在$save()期间,它会在mongoDB中生成一个带有字符串id的新条目?

Node.js 为什么在$save()期间,它会在mongoDB中生成一个带有字符串id的新条目?,node.js,mongodb,angularjs,angularjs-resource,mean-stack,Node.js,Mongodb,Angularjs,Angularjs Resource,Mean Stack,我是个卑鄙的新手。可能是问了个愚蠢的问题 作为练习,我一直在尝试实现一个原型SPA,它在屏幕上显示一系列任务卡(有点像Trello) 目前,每张卡有4个字段: _id:ObjectId 内容:字符串 工作流:字符串 状态:字符串 我正在使用MongoDB作为数据库(使用Robomongo输入一些测试数据),我的机器上安装了node.js,以及Express.js 我的server.js文件如下所示: var express = require('express'), cards =

我是个卑鄙的新手。可能是问了个愚蠢的问题

作为练习,我一直在尝试实现一个原型SPA,它在屏幕上显示一系列任务卡(有点像Trello)

目前,每张卡有4个字段:

  • _id:ObjectId
  • 内容:字符串
  • 工作流:字符串
  • 状态:字符串
我正在使用MongoDB作为数据库(使用Robomongo输入一些测试数据),我的机器上安装了node.js,以及Express.js

我的server.js文件如下所示:

var express = require('express'), 
    cards = require('./routes/cards');

var app = express();

app.configure(function() {
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
});

app.get('/cards', cards.findAll);
app.get('/cards/:id', cards.findById);
app.post('/cards', cards.addCard);
app.put('/cards/:id', cards.updateCard);

app.listen(3000);
console.log('Listening on port 3000...');
    var mongo = require('mongodb');
var Server = mongo.Server,
    Db = mongo.Db,
    BSON = mongo.BSONPure;

var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('mindr', server);
db.open(function(err, db) {
    if(!err) {
        console.log("Connected to 'mindr' database");
        db.collection('cards', {strict:true}, function(err, collection) {
            if (err) {
                console.log("The 'cards' collection doesn't exist.");
            }
        });
    }
});

exports.findById = function(req, res) {
    var id = req.params.id;
    console.log('Retrieving card: ' + id);
    db.collection('cards', function(err, collection) {
        collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
            res.send(item);
        });
    });
};

exports.findAll = function(req, res) {
    db.collection('cards', function(err, collection) {
        collection.find().toArray(function(err, items) {
            res.send(items);
        });
    });
};

exports.addCard = function(req, res) {
    var newCard = req.body;
    console.log('Adding card: ' + JSON.stringify(newCard));
    db.collection('cards', function(err, collection) {
        collection.insert(newCard, {safe:true}, function(err, result) {
            if (err) {
                res.send({'error':'An error has occurred'});
            } else {
                console.log('Success: ' + JSON.stringify(result[0]));
                res.send(result[0]);
            }
        });
    });
}

exports.updateCard = function(req, res) {
    var id = req.params.id;
    var card = req.body;
    console.log('Updating card: ' + id);
    console.log(JSON.stringify(card));
    db.collection('cards', function(err, collection) {
        collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
            if (err) {
                console.log('Error updating card: ' + err);
                res.send({'error':'An error has occurred'});
            } else {
                console.log('' + result + ' document(s) updated');
                res.send(card);
            }
        });
    });
}

exports.deleteCard = function(req, res) {
    var id = req.params.id;
    console.log('Deleting card: ' + id);
    db.collection('cards', function(err, collection) {
        collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
            if (err) {
                res.send({'error':'An error has occurred - ' + err});
            } else {
                console.log('' + result + ' document(s) deleted');
                res.send(req.body);
            }
        });
    });
}
服务器端的Myroutes/cards.js如下所示:

var express = require('express'), 
    cards = require('./routes/cards');

var app = express();

app.configure(function() {
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
});

app.get('/cards', cards.findAll);
app.get('/cards/:id', cards.findById);
app.post('/cards', cards.addCard);
app.put('/cards/:id', cards.updateCard);

app.listen(3000);
console.log('Listening on port 3000...');
    var mongo = require('mongodb');
var Server = mongo.Server,
    Db = mongo.Db,
    BSON = mongo.BSONPure;

var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('mindr', server);
db.open(function(err, db) {
    if(!err) {
        console.log("Connected to 'mindr' database");
        db.collection('cards', {strict:true}, function(err, collection) {
            if (err) {
                console.log("The 'cards' collection doesn't exist.");
            }
        });
    }
});

exports.findById = function(req, res) {
    var id = req.params.id;
    console.log('Retrieving card: ' + id);
    db.collection('cards', function(err, collection) {
        collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
            res.send(item);
        });
    });
};

exports.findAll = function(req, res) {
    db.collection('cards', function(err, collection) {
        collection.find().toArray(function(err, items) {
            res.send(items);
        });
    });
};

exports.addCard = function(req, res) {
    var newCard = req.body;
    console.log('Adding card: ' + JSON.stringify(newCard));
    db.collection('cards', function(err, collection) {
        collection.insert(newCard, {safe:true}, function(err, result) {
            if (err) {
                res.send({'error':'An error has occurred'});
            } else {
                console.log('Success: ' + JSON.stringify(result[0]));
                res.send(result[0]);
            }
        });
    });
}

exports.updateCard = function(req, res) {
    var id = req.params.id;
    var card = req.body;
    console.log('Updating card: ' + id);
    console.log(JSON.stringify(card));
    db.collection('cards', function(err, collection) {
        collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
            if (err) {
                console.log('Error updating card: ' + err);
                res.send({'error':'An error has occurred'});
            } else {
                console.log('' + result + ' document(s) updated');
                res.send(card);
            }
        });
    });
}

exports.deleteCard = function(req, res) {
    var id = req.params.id;
    console.log('Deleting card: ' + id);
    db.collection('cards', function(err, collection) {
        collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
            if (err) {
                res.send({'error':'An error has occurred - ' + err});
            } else {
                console.log('' + result + ' document(s) deleted');
                res.send(req.body);
            }
        });
    });
}
当我从我的AngularJS控制器中的DB获得卡时,一切都很顺利。所有卡片都正确显示在屏幕上。这是获取卡片的代码:

var mindrApp = angular.module('mindrApp', ['ngResource'])

mindrApp.controller('WorkflowController', function ($scope, $resource) {
    var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"@id"});
    $scope.cards = CardService.query();
});
在每张卡上都有一些按钮,可用于将卡的状态更改为工作流中的下一个可用状态(由当前可用状态操作定义)

单击按钮时,卡id和下一个状态将传递给控制器中的函数:

<div class="btn-group btn-group-xs">
    <button type="button" class="btn btn-default" 
        ng-repeat="currentAction in currentState.actions | filter:{default:true}" 
        ng-click="processCard(currentCard._id, currentAction.next)">
        {{currentAction.name}}
    </button>
</div> 
$scope.processCard = function(id, nextState) {
    var currentCard = CardService.get({cardId: id}, function(){
        currentCard.state = nextState;
        currentCard.$save();
    });
};
发生的情况是,当我单击按钮时,不会更改当前卡的状态,而是创建了一个具有String类型的id字段的新卡。这是服务器的输出:

Retrieving card: 52910f2a26f1db6a13915d9f
GET /cards/52910f2a26f1db6a13915d9f 200 1ms - 152b
Adding card: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
Success: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
POST /cards 200 1ms - 150b
知道为什么会这样吗?为什么要在服务器上调用addCard函数而不是调用updateCard函数?

一个$resource对象的$save()操作使用POST作为默认请求类型(阅读更多信息)。因此,在您的情况下,调用了对路由
/cards/:id
的POST请求,因此创建了一张新卡

在server.js中创建新路由条目以处理更新后请求

app.post('/cards/:id', cards.updateCard);
或者添加另一个使用PUT到CardService的操作,并在您想要更新卡时调用它

var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"@id"},
                    { update: { method: 'PUT' } }
                  );

// update the card
...
currentCard.$update();

好吧,我想起来了。我遇到的两个问题是:

1) 它不是更新数据库中的现有项,而是创建一个具有相同ID但采用字符串格式的新项,而不是使用ObjectId格式

2) 每当我调用$update时,它都不会将ID附加到路径,而是始终放在/cards上

下面是每个问题的解决方案

1) 这实际上是一种假设所有id都是ObjectId格式的黑客行为。我不喜欢这个解决方案,但现在它是有效的,我坚持它。我所要做的就是在服务器端的cards.js文件中添加一行代码,将card.id转换回ObjectId格式

exports.updateCard = function(req, res) {
    var id = req.params.id;
    var card = req.body;
    console.log('Updating card: ' + id);
    console.log(JSON.stringify(card));
    card._id = new BSON.ObjectID.createFromHexString(card._id); // HACK!
    db.collection('cards', function(err, collection) {
        collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
            if (err) {
                console.log('Error updating card: ' + err);
                res.send({'error':'An error has occurred'});
            } else {
                console.log('' + result + ' document(s) updated');
                res.send(card);
            }
        });
    });
}
2) 这是一个两部分的修复。首先,我必须修改services.js文件,明确表示我希望通过PUT使用update

    var mindrServices = angular.module('mindrServices', ['ngResource']);
    mindrServices.factory("Card", ["$resource",
    function($resource) {
        return $resource("http://localhost:3000/cards/:cardId", {cardId:"@id"},
            {
                query: {method: "GET", isArray:true},
                update: {method: "PUT"}
            }
        );
    }]);
接下来,我假设只要调用currentCard.$update()就可以从调用实例获取ID,相反,我必须显式地传入ID,如下所示:

var mindrControllers = angular.module('mindrControllers', []);
mindrControllers.controller('CardsController', ["$scope", "Card", 
    function ($scope, Card) {
        $scope.cards = Card.query();
        console.log("cards populated correctly...");

        $scope.processCard = function(currentCard, currentAction) {
            console.log("processCard: card[" + currentCard._id + "] needs to be moved to [" + currentAction.next + "] state... ");
            currentCard.state = currentAction.next;
            currentCard.$update({cardId: currentCard._id}); // passing the ID explicitly
        }
这是我在服务器端得到的输出:

    Updating card: 52910eb526f1db6a13915d9c
{"_id":"52910eb526f1db6a13915d9c","content":"this is some content for this really cool card","workflow":"simple","state":"backlog"}
    1 document(s) updated
    PUT /cards/52910eb526f1db6a13915d9c 200 4ms - 111b

我尝试了两种方法。不幸的是,两者都不起作用。问题是currentCard.$save()和currentCard.$update()都没有传递ID。第一个是过账到/cards,第二个是放入/cards