更新子文件mongoose中的字段

我的父母模型

var GameChampSchema = new Schema({ name: String, gameId: { type: String, unique: true }, status: Number, countPlayers: {type: Number, default: 0}, companies: [ { name: String, login: String, pass: String, userId: ObjectId } ], createdAt: {type: Date, default: Date.now}, updateAt: Date }) 

我需要插入userId属性第一个孩子,他没有设置

所以,只有在条件({status:0,countPlayers:{$ lt:10})

由于这是一个embedded式文档,所以很简单:

如果要更新数组中第一个元素的文档,那么它没有 userId

 db.collection.update( { "status": 0, "countPlayers": {"$lt": 10 }, "companies.userId": {"$exists": false } }, { "$set": {"companies.$.userId": userId } } ) 

这将是很好,但显然这不符合MongoDB如何处理逻辑,它认为没有匹配,如果在数组一些东西存在的字段。 你可以使用聚合框架获得这个元素,但是这对于find我们需要的位置没有帮助。

一个简单的提议是在数组中没有任何元素:

 db.collection.update( { "status": 0, "countPlayers": {"$lt": 10 }, "companies.0": {"$exists": false } }, { "$push": {"userId": userId } } ) 

这只是把一个新的东西在arrays上。

对我来说合乎逻辑的是,你实际上知道这个条目的一些东西,你只是想设置userId字段。 所以我会匹配login:

 db.collection.update( { "status": 0, "countPlayers": {"$lt": 10 }, "companies.login": login, }, { "$set": {"companies.$.userId": userId } } ) 

作为最后一件事,如果这只是更新数组中的第一个元素,那么我们不需要匹配位置,因为我们已经知道它在哪里:

 db.collection.update( { status: 0, countPlayers: {"$lt": 10 } }, { $set: { "companies.0.userId": userId } } ) 

追溯到我的逻辑情况,请参阅文档结构:

 { "_id" : ObjectId("530de54e1f41d9f0a260d4cd"), "status" : 0, "countPlayers" : 5, "companies" : [ { "login" : "neil" }, { "login" : "fred", "userId" : ObjectId("530de6221f41d9f0a260d4ce") }, { "login": "bill" }, ] } 

所以,如果你正在寻找的是“没有userId的第一个文档”,那么这是没有意义的,因为有几个项目,你已经有一个特定的 userId更新。 这意味着你必须是其中的一个。 我们怎么知道哪一个 ? 在用例中,似乎根据您所拥有的信息尝试将那里的信息与userId匹配。

逻辑说,找出你知道的key value ,并更新匹配的位置

只需将db.collection部分replace为您的model对象以用于Mongoose。

请参阅$ exists上的文档,以及$ set和$ push以获取相关详细信息。

十分感谢。

我解决了他的问题

 exports.joinGame = function(req, res) { winston.info('start method'); winston.info('header content type: %s', req.headers['content-type']); //достаем текущего пользователя var currentUser = service.getCurrentUser(req); winston.info('current username %s', currentUser.username); //формируем запрос для поиска игры var gameQuery = {"status": 0, "close": false}; gameChamp.findOne(gameQuery, {}, {sort: {"createdAt": 1 }}, function(error, game) { if (error) { winston.error('error %s', error); res.send(error); } //если игра нашлась if (game) { winston.info('Append current user to game: %s', game.name); //добавляем userId только к одной компании var updateFlag = false; for (var i=0; i<game.companies.length; i++) { if (!game.companies[i].userId && !updateFlag) { game.companies[i].userId = currentUser._id; updateFlag = true; winston.info('Credentials for current user %s', game.companies[i]); //если пользовател последний закрываем игру и отправляем в bw, что игра укомплектована if (i == (game.companies.length-1)) { game.close = true; winston.info('game %s closed', game.name); } } } //сохраняем игру в MongoDB game.save(function(error, game) { if (error) { winston.error('error %s', error); res.send(error); } if (game) { res.send({ game: game }) winston.info('Append successful to game %s', game.name); } }); } }); }