updating objects in double nested arrays in a collection - mongodb

Having this schema:
Task = new SimpleSchema({
_id: {
type: String,
regEx: SimpleSchema.RegEx.Id,
autoValue: function(){ return Random.id(); }
},
title: {
type: String,
label: "Task title",
}
});
Card = new SimpleSchema({
_id: {
type: String,
regEx: SimpleSchema.RegEx.Id,
autoValue: function(){ return Random.id(); }
},
tasks: {
type: [Task],
label: "Card tasks",
optional: true
}
});
ProjectSchema = new SimpleSchema({
name: {
type: String,
label: "Project name"
},
cards: {
type: [Card],
label: "Project cards",
optional: true
}
});
I'm trying to update it with this function, passing the 3 ids and an object with the editted task:
editTask : function(projectId,cardId,taskId,oTask) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
check(projectId, String);
check(cardId, String);
check(taskId, String);
check(oTask, Object);
Projects.update({
_id: projectId,
cards: {
$elemMatch : {
_id: cardId,
tasks : {
_id : taskId
}
}
}
},
{
$set: {"tasks.$.Task": oTask}
});
}
Error says: when the modifier option is true, validation object must have at least one operator.
As far as I know that error means the $set: {"tasks.$.Task": oTask} it's not pointing correctly.
I've also tried: $set: {"cards.tasks.$.Task": oTask},$set: {"cards.$.tasks": oTask}

Related

Change field in object in array of object

I have a field achivment with an array of objects. I need to update the field currentPoints in one object that I will find by field name in the array.
Code model of mongoose:
const achive = new Schema(
{
achiveId: ObjectId,
name: { type: String, required: true },
finishedPoints: { type: Number, required: true },
currentPoints: {
type: Number,
default: 0,
set: function (v) {
if (v >= this.finishedPoints) this.isFinished = true;
return v;
}
},
isFinished: { type: Boolean, default: false }
},
{ _id: false }
);
const achivesSchema = new Schema({
userId: ObjectId,
achivement: [achive]
});
Code query:
export async function progressAchive(req, res) {
const value = 3;
try {
const test = await Achives.updateOne(
{
userId: req.user._id,
achivement: { $elemMatch: { name: req.params.nameAchive } }
},
{ $set: { achivement: { currentPoints: value } } },
{ new: true }
);
res.json(test);
} catch (e) {
console.log(e);
}
}
Instead of updating, it removes all objects from the array and leaves them one object with the currentPoint field. How can I update this like I want?
You should use the following for update
const test = await Achives.updateOne(
{
userId: req.user._id,
},
{
$set:{"achivement.$[el].currentPoints": value}
},
{
arrayFilters:[{
"el.name": req.params.nameAchive
}],
new: true
}
);

Meteor collection2 does not validate on the client side

I am using collection2 with meteor to set default values. However when i run the method Meteor.call('commands.insert', {}) on the client, it just sets new document's ID, and only when the result from server comes it replaces the document with the right value. Actually, autoValue function runs on client because when i console.log there it logs (also tried defaultValue), but it does not do anything, does no modifications, nor unique: true is working, any property specified in the schema
server
export const Commands = new Mongo.Collection('commands')
Commands.schema = new SimpleSchema({
designation: {
type: String,
autoValue: function() {
console.log("inssssssssssssssssssseeeeeeeeeeeeeeeeeeeeeeert")
if (this.isInsert) {
return "Untitled"
}
},
unique: true
},
name: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
syntax: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
description: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
features: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true},
type: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
variants: {
type: Array,
autoValue: function() {
if (this.isInsert) {
return []
}
},
},
'variants.$': {type: String}
})
Commands.attachSchema(Commands.schema)
Meteor.methods({
'commands.insert'(command) {
if (!this.userId) {
throw new Meteor.Error('not-authorized')
}
Commands.insert(command)
}
})
client
const setNewHandler = this.props.page.animationFinished ?
this.props.page.editing ?
textEditorData.length ?
() => {
Meteor.call(
'commands.update',
textEditorData[0]._id,
{
designation:
this.childComponents[0].editableContentNode.textContent,
name:
this.childComponents[1].editableContentNode.textContent,
syntax:
this.childComponents[2].editableContentNode.textContent,
type:
this.childComponents[3].editableContentNode.textContent,
variants:
this.childComponents[4].editableContentNode.textContent.split("\n"),
description:
this.childComponents[5].editableContentNode.textContent,
features:
this.childComponents[6].editableContentNode.textContent
}
)
} :
null :
() => {
Meteor.call('commands.insert', {})
} :
null

Updating array of objects in mongodb

I'm trying to update an array of objects in my simple-schema. Currently, it removes everything in the database and leaves behind:
"careerHistoryPositions": []
My simple-schema looks like:
const ProfileCandidateSchema = new SimpleSchema({
userId: {
type: String,
regEx: SimpleSchema.RegEx.Id
},
careerHistoryPositions: { type: Array, optional: true },
'careerHistoryPositions.$': { type: Object, optional: true },
'careerHistoryPositions.$.uniqueId': { type: String, optional: true },
'careerHistoryPositions.$.company': { type: String, optional: true },
'careerHistoryPositions.$.title': { type: String, optional: true }
});
If console.log form data looks like:
careerHistoryPositions: [Object, Object],
0: Object
company: "Test company"
title: "Test Title"
uniqueId: 1498004350350
1: Object
company: "Test company 2"
title: "Test Title 2"
uniqueId: 149800433221
My update function:
handleFormSubmit(event) {
event.preventDefault();
const { careerHistoryPositions } = this.state;
ProfileCandidate.update({ _id: this.state.profileCandidateCollectionId },
{ $set: {
careerHistoryPositions
}
}
);
}
I managed to fix this by mapping over my object and running 2 separate updates. The first removes the old element and the second adds the updated version. I'm sure there is a better way to do this, however, this does seem to work.
handleFormSubmit(event) {
event.preventDefault();
const { careerHistoryPositions } = this.state;
ProfileCandidate.update({_id: this.state.profileCandidateCollectionId}, { $unset: {
'careerHistoryPositions': {}
}
})
const updatePosition = this.state.careerHistoryPositions.map((position) => {
ProfileCandidate.update({_id: this.state.profileCandidateCollectionId}, { $push: {
'careerHistoryPositions': {
company: position.company,
title: position.title,
uniqueId: position.uniqueId
}
}
})

Simple-schema wont update

I'm trying to update a MongoDB collection using $set. The field within the collection doesn't exist. When I try to add the field, the collection briefly stores the data and then the data disappears and returns an error ClientError: name.first is not allowed by the schema. I have no idea what I'm doing wrong here and I've been searching google for hours.
I'm using:
Meteor
Simple-Schema (NPM)
meteor-collection2-core
Path: Simple-Schema
const ProfileCandidateSchema = new SimpleSchema({
userId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
createdAt: {
type: Date,
},
name: { type: Object, optional: true },
'name.first': { type: String },
});
Path: Method.js
import { Meteor } from 'meteor/meteor';
import { ProfileCandidate } from '../profileCandidate';
import SimpleSchema from 'simpl-schema';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
export const updateContactDetails = new ValidatedMethod({
name: 'profileCandidate.updateContactDetails',
validate: new SimpleSchema({
'name.first': { type: String },
}).validator({ clean: true }),
run(data) {
ProfileCandidate.update({userId: this.userId},
{$set:
{
name: {'first': "Frank"},
}
}, (error, result) => {
if(error) {
console.log("error: ", error)
}
});
}
});
UPDATE
Path: call function
updateContactDetails.call(data, (error) => {
if (error) {
console.log("err: ", error);
console.log("err.error: ", error.error);
}
});
Can you try replacing:
validate: new SimpleSchema({
'name.first': { type: String },
}).validator({ clean: true }),
in Method.js by:
validate: new SimpleSchema({
name: {
type: new SimpleSchema({
first: String,
}),
optional: true,
}).validator({ clean: true }),

Validation object must have at least one operator / meteor mongo

I wrote a method to a user's address to a collection. However, i keep getting the error:
When the modifier option is true, validation object must have at least one operator.
Here is my schema:
var Schemas = {};
Schemas.UserAddress = new SimpleSchema({
streetAddress: {
type: String,
max: 100,
optional: false
},
city: {
type: String,
max: 50,
optional: false
},
state: {
type: String,
regEx: /^[a-zA-Z-]{2,25}$/,
optional: false
},
zipCode: {
type: String,
regEx: /^[0-9]{5}$/,
optional: false
}
});
Schemas.User = new SimpleSchema({
emails: {
type: [Object],
optional: false
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schemas.UserProfile,
optional: false
},
address: {
type: Schemas.UserAddress,
optional: false
},
services: {
type: Object,
optional: true,
blackbox: true
}
});
Meteor.users.attachSchema(Schemas.User);
And here is my addAddress event:
Template.editAddress.events({
'click .addAddress': function(e, tmpl) {
e.preventDefault();
var currentUserId = this._id;
var addressDetails = {
address: {
streetAddress: $('#streetAddress').val(),
city: $('#city').val(),
state: $('#state').val(),
zipCode: $('#zipCode').val()
},
};
console.log(addressDetails);
Meteor.call('addNewAddress', addressDetails, currentUserId, function(error) {
if (error) {
alert(error.reason);
} else {
console.log('success!');
Router.go('Admin');
}
});
},
});
Here's my addAddress method:
Meteor.methods({
'addNewAddress': function(addressDetails, currUserId) {
var currentUserId = currUserId;
Meteor.users.update(currentUserId, {$addToSet:
{'address.streetAddress': addressDetails.streetAddress,
'address.city': addressDetails.city,
'address.state': addressDetails.state,
'address.zipCode': addressDetails.zipCode
}
});
}
});
Note - when I do console.log(addressDetails), it prints out the address details just fine.
Can someone help? Thank you in advance!!
Yeah, that error kinda sends you in the wrong direction. Regardless, you're using $addToSet on an object. Do this:
Meteor.users.update(currentUserId, {$set: addressDetails.address}
Try the following code:
Meteor.users.update(
{$currUserId},
{$addToSet:
{'address.streetAddress': addressDetails.streetAddress,
'address.city': addressDetails.city,
'address.state': addressDetails.state,
'address.zipCode': addressDetails.zipCode
}
});