Find document by ID and push another subdocument - express

I have two Collection schemas, and I want to insert one Model instance of one schema (FA) inside an array field of the other Model schema (FP):
var FASchema = new Schema({
Timestamp: Date,
PrognostizierterBetriebswert: Number,
posFlexPot: Number,
negFlexPot: Number,
Leistungsuntergrenze: Number,
Leistungsobergrenze: Number,
posGesEnergie: Number,
negGesEnergie: Number,
Preissignal: Number,
Dummy1: Schema.Types.Mixed,
Dummy2: Schema.Types.Mixed,
Dummy3: Schema.Types.Mixed
//same: Dummy: {}
});
module.exports = mongoose.model("FA", FASchema, 'FA');
and
var FPSchema = new Schema( {
_id: String, //mongoose.Schema.Types.ObjectId,
Demonstrator: Number,
erstellt: {type: Date, 'default': Date.now},
von: Date,
bis: Date,
Fahrplanabschnitte: { type: Schema.Types.ObjectId, ref: 'FA' },
})
module.exports = mongoose.model("FP", FPSchema, 'FP');
Now, whenever I create a new FA document, I want to push the FA document into my FP collection inside the array "Fahrplanabschnitte". Either by a reference, or by a schema/nested subdocument... What is the best way to do it and how can I do it?
I call the POST method that should do the job with: router.route('/FA/FPPUT/:FP_id').put(FAController.create_and_push_to_FP_by_ID)
The function itself looks like this:
In a first step, a FA instance is created and saved in FA Collection, then the FP collection is updated and into the array "Fahrplanabschnitte", the new FA instance should be inserted. However, it does not work as planned..
exports.create_and_push_to_FP_by_ID=function(req,res) {
console.log(req.body)
var fa = new FA(req.body);
//SAVE the new instance
fa.save(function(err) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FA in Datenbank erzeugt!");
res.status(200);
res.json({ message: 'FA-Instance created in datbase!' })
}
});
FP.findOneAndUpdate({_id: req.params.FP_id}, function(err, fp) {
if (err){
res.send(fa);
}
//res.json(fp);
fp.Fahrplanabschnitte.push(fa._id);
})
};
What am I doing wrong?

You are going wrong here
`fp.Fahrplanabschnitte.push(fa._id); //does't make sense at all`
above line doesn't do or update anything to the mongodb database...
you need to use $push operator to update the collection in the
database
exports.create_and_push_to_FP_by_ID=function(req,res) {
console.log(req.body)
var fa = new FA(req.body);
//SAVE the new instance
fa.save(function(err, fa) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FA in Datenbank erzeugt!");
FP.findOneAndUpdate({_id: req.params.FP_id}, { $push: {
Fahrplanabschnitte: fa._id } } function(err, fp) {
if (err){
return res.send(fa);
}
res.status(200);
res.json({ message: 'FA-Instance created in datbase!' })
})
}
});
};

Related

Mongoose update gets no errors, but does not update

Cant figure out what I'm missing, and I havent had this issue before on any of my other updates. I expanded a collection and want to be able to update certain fields depending on where in the app the user is interacting. I've had no issue working with subdocs using separate calls, but with this particular nested field I'm getting no errors, and getting the correct document returned without the update. (I have another nested field that is updating fine - "personalInfo" while the "medical" field is the one giving me trouble)
The model looks like this:
const clientSchema = new Schema({
fullName: String,
firstName: String,
lastName: String,
enrollment: {
enrolled: Boolean,
enrollDates: [
{
begin: Date,
end: Date
}
]
},
personalInfo: {
dateOfBirth: Date,
phone: String,
email: String,
address: {
addressLineOne: String,
addressLineTwo: String,
city: String,
state: String,
zip: String
},
regionalCenter: String,
serviceCoordinator: String,
serviceCoordinatorPhone: String,
rcId: String,
emergencyContact: String,
livingSituation: String,
ihss: {
provider: String,
hours: Number,
services: String
}
},
medical: {
primaryIns: String,
primaryInsId: String,
secondaryIns: String,
secondaryInsId: String,
hasMediCal: Boolean,
mediCalId: String,
mediCalEnroll: Date,
hasMedicare: Boolean,
medicareId: String,
medicareEnroll: Date,
logs: {type: [logSchema], default: []},
},
contracts: {type: [contractSchema], default: []},
visits: [{ type: Schema.Types.ObjectId, ref:'Visit' }],
users: [{ type: Schema.Types.ObjectId, ref: 'User' }],
servicePlans: [{ type: Schema.Types.ObjectId, ref: 'ServicePlan'}],
currentPlan: String,
income: {type: [incomeSchema], default: []},
contacts: {type: [contactSchema], default: []}
}
The route:
router.route("/clients/:clientId").patch(updateClient)
And the controller... since I want to keep the controller as restful as possible, but conditionally set the fields depending on the api call, I conditionally set the different aspects and then pass in the body an additional field to tell the controller which aspect to update (so the personalInfo section has a field "personalInfo": "personalInfo" and the medicalInfo field has its own. The personalInfo object updates fine (I commented out the initial line since it was stated in another post that these calls work better doing a findOneAndUpdate- but that hasnt yielded any progress, and the personalInfo update worked without issue).
exports.updateClient = async (req, res) => {
try {
//const client = await Client.findOne({ _id: req.params.clientId })
if (req.body.firstName) {
client.firstName = req.body.firstName
}
if (req.body.lastName) {
client.lastName = req.body.lastName
}
if (req.body.personalInfo === 'personalInfo') {
client.updateOne({$set: {personalInfo: req.body}}, {new: true}, function(err, updatedDoc){
if(err){
console.log("error updating personal info: ", err)
}
})
}
if (req.body.enrollment === 'enrollment') {
client.updateOne({$set: {enrollment: req.body}}, {new: true}, function(err, updatedDoc){
if(err){
console.log("error updating personal info: ", err)
}
})
}
if(req.body.medicalInfo === 'medicalInfo'){
console.log("medInfo: ", req.body)
let clientId = req.params.clientId
// const client = await Client.findById(clientId)
// console.log("Client ", client)
// client.medical.set(req.body)
Client.findById(clientId)
.then((client) => {
client.medical.set(req.body
// hasMediCal: req.body.hasMediCal,
// hasMedicare: req.body.hasMedicare,
// mediCalId: req.body.mediCalId,
// medicareId: req.body.medicareId,
// mediCalEnroll: req.body.mediCalEnroll,
// medicareEnroll: req.body.medicareEnroll,
// primaryIns: req.body.primaryIns,
// primaryInsId: req.body.primaryInsId,
// secondaryIns: req.body.secondaryIns,
// secondaryInsId: req.body.secondaryInsId
);
client.save();
res.send(client)
})
// Client.findOneAndUpdate(
// { _id: req.params.clientId},
// {$set: {medical: req.body}},
// {new: true},
// function(err, updatedDoc){
// if(err){
// console.log("error updating personal info: ", err)
// }
// })
// client.markModified('medical');
}
// await client.save()
// res.send(client)
} catch (error) {
res.status(404)
res.send({ error: "Client not updated: ", error})
}
}
Finally, the body being sent:
{
"hasMediCal": false,
"hasMedicare": false,
"mediCalEnroll": "2005-04-22T08:00:00",
"mediCalId": "91234567A",
"medicalInfo": "medicalInfo",
"medicareEnroll": "2005-04-03T08:00:00",
"medicareId": "9FHS-ASU-95F8",
"primaryIns": "Molina",
"primaryInsId": "91234567A",
"secondaryIns": "SilverScript - Rx",
"secondaryInsId": "08dfA8d8"
}
Whether I've tried findOneAndUpdate, or findOne and then setting the field on the result, or setting each subfield in the object specifically, I keep getting the correct document returned, just not updated, and with no errors. I thought possibly it was because I was attempting to set the update within the conditionals, so I created a separate update controller but that got the same results as well. Really lost as how else to pursue this.
Please let me know if you see anything missing or where I'm going wrong. Much appreciated.
So after running around on this for hours, I came to a working solution, which essentially is no different, other than setting the query as a variable rather than writing it out. If anyone has any guess as to why this works when the multiple other methods didnt, I'd be grateful for your thoughts.
if(req.body.medicalInfo === 'medicalInfo'){
console.log("medInfo: ", req.body)
let clientId = req.params.clientId
let query = {_id: clientId};
Client.findOneAndUpdate(query, {$set: {medical: req.body}}, {new: true, upsert: true}, function(err, doc){
if(err) return res.status(500).send( {error:err});
return res.send(doc)
})
}

mapPropertyErrors seems to only return null

I can't seem to get the automatic error messages working. My configuration seems to be correct from what I've read online, yet the error always get's picked up in the catch after using the repository.save(entity) function. I'm specifically trying to get an error related to leaving the field empty but :required="true" doesn't seem to help. Could it be because they are translation fields? My entity is called suiteseven_usp.
I've got the following definition:
protected function defineFields(): FieldCollection
{
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new Required(), new PrimaryKey()),
(new TranslatedField('text'))->addFlags(new ApiAware(), new Required()),
(new TranslatedField('subtext'))->addFlags(new ApiAware(), new Required()),
new StringField('icon', 'icon'),
new StringField('type', 'type'),
new TranslationsAssociationField(UspTranslationDefinition::class, 'suiteseven_usp_id'),
]);
}
The following in computed: in my component:
...mapPropertyErrors('suiteseven_usp', [
'text',
'subtext'
]),
And this as one of the fields:
<sw-field
v-model="usp.text"
class="s7-usp-detail__text"
:label="$tc('s7-usp.detail.fieldTextLabel')"
:placeholder="$tc('s7-usp.detail.fieldTextPlaceholder')"
:disabled="!acl.can('usp.editor')"
:error="suitesevenUspTextError"
:required="true"
></sw-field>
This is my save function:
onSave() {
this.isLoading = true;
this.isSaveSuccessful = false;
return this.uspRepository.save(this.usp, Shopware.Context.api).then(() => {
this.isSaveSuccessful = true;
this.createNotificationSuccess({
title: this.$tc('global.default.success'),
message: this.$tc('s7-usp.detail.notificationSuccessMessage'),
});
if (!this.uspId) {
this.$router.push({name: 's7.usp.detail', params: {id: this.usp.id}});
}
this.uspRepository.get(this.usp.id, Shopware.Context.api).then((updatedUsp) => {
this.usp = updatedUsp;
this.isLoading = false;
});
}).catch(() => {
this.createNotificationError({
title: this.$tc('global.default.error'),
message: this.$tc('s7-usp.detail.notificationErrorMessage'),
});
this.isLoading = false;
});
},
You also need to set Required flag to TranslationsAssociationField also.
(new TranslationsAssociationField(UspTranslationDefinition::class, 'suiteseven_usp_id'))->addFlags(new Required()),

Array being populated by itself

I'm having am issue with an array that seems to be getting populated with my mongoose code by itself. It's making it impossible to populate the array with modified values.
Here's the code:
router.get('/in-progress', function(req, res) {
console.log('exporting');
var dataset = [];
Intake.find({}, function(err, intakes) {
if(err){
console.log(err);
} else {
/*intakes.forEach(function(intake) {
dataset.push(
{
//requestName: intake.requestName,
requestName: 'Request Name',
status: intake.phase
}
)
});*/
return dataset;
}
}).then((dataset) => {
console.log(dataset);
const report = excel.buildExport(
[
{
heading: inProgressHeading,
specification: inProgressSpec,
data: dataset
}
]
);
res.attachment('requests-in-progress.xlsx');
return res.send(report);
});
});
As you can see, the logic to push data to "dataset" is commented out, but the console log is logging every Intake that I have in the MongoDB database. Does anyone know what I am doing wrong so that I can push my own values into "dataset"?

How to avoid duplicate entries in IBM JSONStore

WL.JSONStore.get(collectionName).change(data, options) method does not seem to work for duplicate values. I get duplicate values entered whenever data is loaded through the adapter. Below is the code that I have used to avoid duplicate entries.
init(){
console.log('JSONStore init function callled');
let collections = {
activities: {
searchField: {serialKey: 'string'},
adapter: {
name: 'ServiceAdapter',
add: 'pushActivities',
remove: 'removeActivity',
replace: 'replaceActivity',
load: {
procedure: 'getActivities',
params: [],
key: 'rows'
}
}
}
}
WL.JSONStore.init(collections).then((success) => {
console.log('-->JSONStore init success')
}, (failure) => {
console.log('-->JSONStore init failed', failure)
})
}
load() {
let dataRequest = new
WLResourceRequest("/adapters/ServiceAdapter/getActivities",
WLResourceRequest.GET);
dataRequest.send().then(
(response) => {
this.data = response.responseJSON.rows;
this.activityService.put(this.data);
})
}
put(data){
console.log('--> JSONStore put function called');
let collectionName = 'activities';
let options = {
replaceCriteria: ['serialKey'],
addNew: true,
markDirty: false
};
WL.JSONStore.get(collectionName).change(data, options).then((success) => {
console.log('--> JSONStore put success')
}, (failure) => {
console.log('--> JSONStore put failed', failure)
})
}
Adapter Function:
function getActivities() {
var path = 'employees' + '/_all_docs?include_docs=true';
var input = {
method : 'get',
returnedContentType : 'json',
path : path,
};
var response = MFP.Server.invokeHttp(input);
if (!response.rows) {
response.isSuccessful = false;
return response;
} else {
var results = [];
for (var i=0; i < response.rows.length; i++) {
results.push(response.rows[i].doc);
}
return {'rows': results};
}
}
I have even tried by:
searchFields: {serialKey: 'string',serialId: 'string'}
replaceCriteria: ['serialKey','serialId']
But no luck.
NOTE: There is no error in the former one, whereas the later results in an error.
ERROR : PROVISION_TABLE_SEARCH_FIELDS_MISMATCH (I have already tried to destroy the collection and perform the change, as the link suggests.
I have followed the below link:
https://www.youtube.com/watch?v=Ep6w1zXoI-k
I am using the below versions:
mfpdev : 8.0.0-2017102406
Let me know if you need any more details.

How to omit fields when serializing Mongoose models in MEAN [duplicate]

I have the following simple shema:
var userSchema = new Schema({
name : String,
age: Number,
_creator: Schema.ObjectId
});
var User = mongoose.model('User',userSchema);
What I want to do is create the new document and return to client, but I want to exclude the 'creator' field from one:
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
res.json(200, {user: user}); // how to exclude the _creator field?
});
});
At the end I want to send the new created user without _creator field:
{
name: 'John',
age: 45
}
Is it possible to make without extra find request to mongoose?
P.S:It's preferable to make it by
Another way to handle this on the schema level is to override toJSON for the model.
UserSchema.methods.toJSON = function() {
var obj = this.toObject()
delete obj.passwordHash
return obj
}
I came across this question looking for a way to exclude password hash from the json i served to the client, and select: false broke my verifyPassword function because it didn't retrieve the value from the database at all.
The documented way is
UserSchema.set('toJSON', {
transform: function(doc, ret, options) {
delete ret.password;
return ret;
}
});
UPDATE - You might want to use a white list:
UserSchema.set('toJSON', {
transform: function(doc, ret, options) {
var retJson = {
email: ret.email,
registered: ret.registered,
modified: ret.modified
};
return retJson;
}
});
Come across your question when I was trying to find a similar answer with pymongo. It turns out that in mongo shell, with the find() function call, you can pass a second parameter which specifies how the result document looks like. When you pass a dictionary with attribute's value being 0, you are excluding this field in all the document that come out of this query.
In your case, for example, the query will be like:
db.user.find({an_attr: a_value}, {_creator: 0});
It will exclude _creator parameter for you.
In pymongo, the find() function is pretty much the same. Not sure how it translate to mongoose though. I think it's a better solution compare to manually delete the fields afterwards.
Hope it helps.
I would use the lodash utilities .pick() or .omit()
var _ = require('lodash');
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
// Only get name and age properties
var userFiltered = _.pick(user.toObject(), ['name', 'age']);
res.json(200, {user: user});
});
});
The other example would be:
var _ = require('lodash');
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
// Remove _creator property
var userFiltered = _.omit(user.toObject(), ['_creator']);
res.json(200, {user: user});
});
});
You can call toObject() on the document to convert it to a plain JS object that you can freely modify:
user = user.toObject();
delete user._creator;
res.json(200, {user: user});
By following the MongoDB documentation, you can exclude fields by passing a second parameter to your query like:
User.find({_id: req.user.id}, {password: 0})
.then(users => {
res.status(STATUS_OK).json(users);
})
.catch(error => res.status(STATUS_NOT_FOUND).json({error: error}));
In this case, password will be excluded from the query.
font: https://docs.mongodb.com/v2.8/tutorial/project-fields-from-query-results/#return-all-but-the-excluded-field
I am using Mongoosemask and am very happy with it.
It does support hiding and exposing properties with other names based on your need
https://github.com/mccormicka/mongoosemask
var maskedModel = mongomask.mask(model, ['name', 'age']); //And you are done.
You can do this on the schema file itself.
// user.js
var userSchema = new Schema({
name : String,
age: Number,
_creator: Schema.ObjectId
});
userSchema.statics.toClientObject = function (user) {
const userObject = user?.toObject();
// Include fields that you want to send
const clientObject = {
name: userObject.name,
age: userObject.age,
};
return clientObject;
};
var User = mongoose.model('User',userSchema);
Now, in the controller method where you are responding back to the client, do the following
return res.json({
user: User.toClientObject(YOUR_ENTIRE_USER_DOC),
});