I am trying to update a collection by pushing to an already existing array in the collection.
Here is the update function I am trying to run:
Games.update({ _id: game._id }, {
$push: { players: { name: playerName } },
});
Here is the error I am getting in the console:
update failed: MongoError: Cannot update 'players' and 'players' at the same time
Relevant schemas:
Player = new SimpleSchema({
name: {
type: String,
label: 'name',
max: 50,
},
});
Schemas.Game = new SimpleSchema({
...
players: {
type: [Player],
label: 'Players',
autoValue: function () {
return [];
},
},
});
I am using the autoValue for the players array to sort of initialize it when a new game is created. Could this be a problem for when the first player is added?
Some help would be appreciated.
Edited: #Logiwan992 try using defaultValue instead of autoValue.I believe you're using autoValue to set the value of players so it isn't undefined. But with your implementation, autoValue would run when there is an update on your document.
defaultValue would run when the document is created first. But if you still choose to use autoValue, you may also want to check if it's an update and return undefine. As in this
players: {
type: [Player],
label: 'Players',
autoValue: function () {
if (this.isUpdate) {
return undefined;
}
return [];
},
},
Returning undefined would ensure the new update value is used.
My recommendation though is to use
players: {
type: [Player],
label: 'Players',
defaultValue: [],
},
Related
My data model:
{
_id: ObjectId,
persons:[{
_id: ObjectId,
name: String,
...
}],
relations: [{
type: String,
personId: ObjectId,
...
}],
...
}
Here's my issue:
I am trying to find documents where person's name is x and it's _id is inside the relations array (personId) with a given type.
Example:
My data:
[{
_id:"1",
persons:[{
_id:"1",
name: "Homer"
},
{
_id:"2",
name: "Bart"
}],
relations: [{
type:"House_Owner",
personId: 1,
}],
}]
Request_1:
Find all documents where "Homer" is the house owner
Result:
[{
_id:"1",
...
}]
Request_2:
Find all documents where "Bart" is the house owner
Result:
[]
Any help would be appreciated.
The only solution I see here is to do the find operation with the given name value and after that filter the mongodb result.
PS: I cannot change the existing data model
EDIT:
I found a solution to do this by using $where operator with a javascript function but I am not sure that's the most efficient way.
db.myCollection("x").find({
$where: function() {
for (const relation of this.relations) {
if(relation.type === "House_Owner") {
for (const person of this.persons) {
if(person.name === "Homer" && person._id.equals(relation.personId)) {
return true;
}
}
}
}
}
})
You can do something like this:
const requiredName="x"
const requiredId = "id"
await yourModel.find({$and:[{"relations.personId":requiredId },{"persons.name":requiredName}]})
I have a Schema that holds an array of objects for comments and I would like to update the boolean value of the flagged comments accordingly, I have tried updateOne and aggregate but it isn't working out at this point, I have also tried to use $elemMatch but it isn't working.
The comment _id is being pulled from the front end element that has an ID that is the same as the id that needs to be pulled from MongoDB.
Comments Array within the question Schema:
comments: [
{
user: {
type: Object,
},
commentDate: {
type: Date,
default: Date.now()
},
flagged: {
type: Boolean,
default: false
},
flaggedDate:{type: Date},
comment: String,
}
],
function I tried to run last.
const id = req.params.id
const updateFlag = Question.updateOne(
{
comments: [
{
_id: id
}
]
},
{
$set: {
comments: [
{
flagged: req.body.flagged
}
]
}
}
)
Any help would be appreciated!
You can do it with positional operator - $:
db.collection.update({
"comments._id": "3"
},
{
"$set": {
"comments.$.flagged": true
}
})
Working example
I have to do an update on the following Mongoose Model.
var room_schema = new Schema({
title: { type: String, required: true },
questions: [{ //array of reflections
q_index: {type: Number},
q_text: { type: String},
responses: [{ //array of
student: { type: Schema.Types.ObjectId, ref: 'User' },
response: { type: String }
}]
}]
});
module.exports = mongoose.model('Room', room_schema);
Required values are in an object as
x = {
room: ObjectId("586a0aa0232a3918c8b7f5c9"),
student: ObjectId("5863918c85c9ba0aa0232a7f"),
question: 0,
msg: "Some Message"
}
Now, i want to update the room. I tried doing something like this
Room.update(
{_id:x.room,
'questions.q_index':x.question,
'questions.responses.student':x.student},
{$set:{
'responses.$.student.response' : x.msg
}},function(err, data){
if(err){throw err}
console.log(data);
}
);
The msg which is being returned is { ok: 0, n: 0, nModified: 0 } and needless to say the update is not happening.
Also, there is a possibility that the Room may not have a response array in it. And i expect that, if that is the case, then the array should be created and then updated.
Please give me some guidance.
Sry, but I can't write a comment since I don't have enough of rep, so I'm forced to write my notice as an answer.
I notice something in your first query when you search for a room by it's _id. Try to put _id in quotes like this "_id", because it should be like this relating to this post
stackoverflow: updating-an-array-inside-a-mongoose-model
For arrays vue.js good works with default array methods: push, pop, shift, reverse... But how to create new item in object and paste some value?
new Vue({
el: '#demo',
data: {
items: [
{
start: '12:15',
end: '13:15',
name: 'Whatch Vue.js Laracast',
description: 'Watched the Laracast series on Vue.js',
tags: ['learning', 'Vue.js', 'Laracast', 'PHP'],
note: "Vue.js is really awesome. Thanks Evan You!!!"
},
{
start: '13:15',
end: '13:30',
name: "Rubik's Cube",
description: "Play with my Rubik's Cube",
tags: ['Logic', 'Puzzle', "Rubik's Cube"],
note: "Learned a new algorithm."
}
],
},
methods: {
addItemAttribute: function(name, text) {
this.items[0][name] = text;
}
}
});
You can add properties to a Vue object similar to a normal javascript object. Reference: https://vuejs.org/api/#Options-Data
var obj = { a: 1};
obj.a // 1
obj.b // undefined
obj.b = 2;
// Now obj.b is defined
obj.b // 2
You can access data from Vue object like this
var vm = new Vue({
data: {
a: 1,
b: 2
}
});
Now we can access data from $data property
vm.$data.a === 1;
// You can add a new property
vm.$data.c = 3;
// it can be any object
vm.$data.d = {id: 1, name: 'ABC'}
You get and update props of a component using component.options.props
var component = Vue.component('props-demo-advanced', {
props: {
// just type check
size: Number,
// type check plus other validations
name: {
type: String,
required: true,
// warn if not two way bound
twoWay: true
}
}
});
Let's say, we want to make name twoWay binding to false
component.options.props.name.twoWay = faslse
Or even you can change the entire object.
component.options.props = {
size: Number,
type: {
type: Number,
required: false,
twoWay: false
}
}
I don't know the above configurations are correct or not, I am just trying to convey the idea.
You should learn Javascript first, how objects are made, how to change them etc.
i am trying to push inside a subarray using $push but got a Mongo error, and not able to get through this after considerable search on google, and findOneAndUpdate didn't worked out so i used find and update separately
{ [MongoError: can't append to array using string field name: to]
name: 'MongoError',
err: 'can\'t append to array using string field name: to',
code: 13048,
n: 0,
lastOp: { _bsontype: 'Timestamp', low_: 2, high_: 1418993115 },
Schema:
var NetworkSchema = new Schema({
UserID: {
type: Schema.Types.ObjectId,
ref: 'User'
},
NetworkList: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
NetworkRequest: [{
from: [{
type:Schema.Types.ObjectId,
ref: 'User'
}],
to: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}]
});
Document:
{
"UserID" : ObjectId("549416c9cbe0e42c1adb42b5"),
"_id" : ObjectId("549416c9cbe0e42c1adb42b6"),
"NetworkRequest" : [
{
"from" : [],
"to" : []
}
],
"NetworkList" : [],
"__v" : 0
}
Controller:
exports.update = function(req,res) {
var network = req.network;
var query={'UserID':req.body.UserID};
var update = {$push:{'NetworkRequest.to': req.body.FriendID}};
Network.find(query,function(err){
if (err) {
console.log(err);
return err;
} else {
}
});
Network.update(query,update,{upsert:true},function(err,user){
console.log(user);
if (err) {
console.log(err);
return err;
} else {
console.log('User'+user);
}
});
};
Everything #cbass said in his answer is correct, but since you don't have a unique identifier in your NetworkRequest element to target, you need to do it by position:
var query = {'UserID': req.body.UserID};
var update = {$push:{'NetworkRequest.0.to': req.body.FriendID}};
Test.update(query, update, {upsert: true}, function(err, result) { ... });
'NetworkRequest.0.to' identifies the to field of the first element of the NetworkRequest array.
Your query var query={'UserID':req.body.UserID}; identifies the document you want to edit. Then you need another query to identify which object in the NetworkRequest array that the UserID should be pushed into. Something like below:
var query = {
'UserID':req.body.UserID,
'NetworkRequest._id': ObjectId(someNetworkRequestId)
};
Then use this update query containing $ which is the index of the object in the nested array(NetworkRequest)
var update = {
$push:{
'NetworkRequest.$.to': req.body.FriendID
}
};