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
}
}
})
Related
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
}
);
I need to update different fields of a nested array in Mongoose. Sometimes I will send runId and runStatus, some other times siteFetched and some other times siteInfo.
I have tried with the following code but the $set operator replaces the old fields.
The model:
campaignId: { type: String },
keywords: [{
keyword: { type: String },
serp: {
runId: { type: String },
runStatus: { type: String },
siteFetched: { type: Boolean },
sitesInfo: [{
title: { type: String },
url: { type: String },
description: { type: String },
}],
},
},
],
Here is the code to update
const campaign = await Campaign.findOneAndUpdate(
{ _id: campaignId, "keywords.keyword": keyword },
{
$set: { "keywords.$.apifySerp": {...serp }},
}
);
the value for serp varies like
const serp = {
runId: '1kLgbnvpADsDJyP1x',
runStatus: 'READY'
}
and
const serp = {
siteFetched: true
}
Here is the code that solved my problem.
const serp = {
siteFetched: true,
};
let update = Object.keys(serp).reduce((acc, cur) => {
acc[`keywords.$.apifySerp.${cur}`] = serp[cur];
return acc;
}, {});
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
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}
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
}
});