I am attempting to save an update to my subdocument, but when I save the parent document disappears (thus loosing all the data including the update).
Here is my route:
router.put('/input/:parentid/:childid', urlencodedParser, function(req, res, next){
// Update Already Created Incident
async function update(id){
let checkedUnits = [];
let timeEntries = [];
recall = [];
units.forEach(unit => {
if(req.body[unit.id]){
checkedUnits.push(unit._id);
}
});
// console.log(personnel);
personnel.forEach(person => {
if(req.body[person._id]){
let PERSON = {person: {personId: person._id}}
recall.push(PERSON);
}
});
//===================FIND PARENT DOCUMENT===================================//
CallData.findOne({_id: id}, (err, doc)=>{
//====================TARGET CORRECT SUBDOCUMENT by id =====================//
subdoc = doc.incidents.id(req.params.childid);
//===========================UPDATE DOCUMENT=============================//
date = moment(req.body.dispatchDate).format('YYYY-MM-DD')
doc.date=date,
subdoc.incidentNumber = req.body.incidentNumber;
subdoc.callType = req.body.callType;
subdoc.times.dispatch = moment(req.body.dispatchDate).format('MM/DD/YY')+' '+req.body.dispatchTime;
subdoc.times.clear = moment(req.body.clearDate).format('MM/DD/YY')+' '+req.body.clearTime;
subdoc.address.placeName = req.body.locationName;
subdoc.address.streetAddress = req.body.streetAddress;
subdoc.address.apt = req.body.apt;
if(req.body.disposition !== "Choose..."){
subdoc.disposition.selected = req.body.disposition;
}
subdoc.disposition.typed = req.body.other;
subdoc.units = checkedUnits;
subdoc.recall = recall;
//==============Save Document===============//
doc.save(err=>{if(err){console.log(err)}); //<==============No error thrown here.
res.json(doc); //<==================Produces a correct json of the updated doc.
});
}
update(req.params.parentid);
});
Once the above runs on a document it disappears from the database. I am not sure why doc.save is deleting the doc.
I have tried using async/await, and CB. I am unsure how else to select the correct subdocument in the subdocument array. Mongoose's docs say to do the ```parent.sub.id(_id)`` to select it but I have a feeling this is where I am going wrong.
Thank you for any insight.
-Adam
The answer was here:
date = moment(req.body.dispatchDate).format('YYYY-MM-DD')
It was changing the date format and therefore I could not find my data, I thought it was being deleted it was not. Just being changed.
I have corrected the code to:
date = moment(req.body.dispatchDate).format('YYYY/MM/DD')
And now I it works beautifully.
Thanks for the help.
Related
I have a table called "UserAnswers".below screenshot contains table data
I want to get data by surveyId and group by CreatedBy column.
for an example
There is a user called "amara#gmail.com".this user contains 4 records for a SurveyId.
I want to get this like below
Answers : [
{"2"},
{"1","0","1","1"},
{"1","2","4","3"},
{"Blue"}]
But my code returns this array for every rows.I meant duplicate records returning.
Here is my code
var qstns = await (from uans in _context.UserAnswers
where uans.SurveyId == id
select new UserAnswersReturnDto
{
UserEmail = uans.CreatedBy,
Qustns = (from ans in _context.UserAnswers
where ans.CreatedBy == uans.CreatedBy
select new UserAnswersSet
{
QNo = ans.QNo,
Ansrs = JsonConvert.DeserializeObject<JArray>(string.IsNullOrEmpty(ans.Answers) ? "[]" : ans.Answers)
}).ToArray()
}).ToListAsync();
So how to solve this issue.I opened many questions for this problem,but no one answered.Please help me.Thanks in advanced
You need to actually group your data before returning:
I used LINQ Lambda notation, but it should be quite easy to translate back to query if you're so inclined:
var qstns = _context.UserAnswers.Where(uans => uans.SurveyId == id)
.GroupBy(uans => uans.CreatedBy)
.Select(grans => new UserAnswersReturnDto {
UserEmail = grans.Key,
Qustions = grans.Select(ans => new UserAnswersSet() {
QNo = ans.QNo,
Ansrs = ans.Answers
}).ToList()
} ).ToList();
I didn't have time to double-check this, but I hope it serves as a guide to help you solve your issue!
There is no group by statement in your linq query.
I recently found out how to change the value of an existing property and saving it to the mongo database when using Keystone JS (How to alter a value before storing it to the database in Keystone JS).
Now I need to add a new property and save it to the database during the same pre('save') phase.
The aims is to say, if the result (existing property) of a game is 'Won', then add a new property 'won' which is a boolean (true). If it matters, the reason I want this is because in a handlebars template I want to say {{#if won}}class="success"{{/if}}
Game.schema.pre('save', function(next) {
if (this.isModified('result')) {
if (this.result === 'Won') {
this.won = true;
}
}
next()
});
But nothing happens. I read that you can't add properties unless they've been set in the schema. So I tried adding Game.schema.set('won', false); above that, but still nothing.
Is there a simple way to do this?
You could look at Mongoose virtuals which are properties that you can get and set but that do not get persisted to the database:
Game.schema.virtual('won').get(function() {
return this.result === 'Won'
})
http://mongoosejs.com/docs/guide.html#virtuals
If you just want to use it in your template then you could also set a specific property on locals in your view.
Perhaps something like this:
...
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res)
var locals = res.locals
locals.games = []
view.on('init', function(next) {
var query = {} // Add query here
Game.model.find(query).exec(function(err, games) {
// Handle error
games.forEach(function(game) {
game.won = game.result === 'Won'
})
locals.games = games
})
})
}
...
I know there's a way to do db.collection.getIndexes() Which will list all the indexes defined for a collection. Is there a way to copy and create those index definitions to another collection?
There's a lot of them and I don't want to do them one by one.
regarding the duplicated question comment: I do not wish to copy a collection. I wish to export indexes in a format that I can apply to another collection.
For example I have one existing user collection with indexes _id_, name_1, email_1 and website_1
Then I have another collection called usertest, I want to copy indexes from user collection to usertest collection. The following commands works for this scenario:
Copy both index key and index options
var indexes = db.user.getIndexes();
indexes.forEach(function(index){
delete index.v;
delete index.ns;
var key = index.key;
delete index.key
var options = [];
for (var option in index) {
options.push(index[option]);
}
db.usertest.createIndex(key, options);
});
Copy index key only (batch processing)
var indexKeys = db.user.getIndexKeys();
db.usertest.createIndexes(indexKeys);
Hope this will be helpful. Here's the doc: createIndexes
To do this directly in MongoDB do the following,
The following command will generate mongo DB queries for existing indexes of all collections,
db.getCollectionNames().forEach(function(col) {
var indexes = db[col].getIndexes();
indexes.forEach(function (c) {
var fields = '', result = '', options = {};
for (var i in c) {
if (i == 'key') {
fields = c[i];
} else if (i == 'name' && c[i] == '_id_') {
return;
} else if (i != 'name' && i != 'v' && i != 'ns') {
options[i] = c[i];
}
}
var fields = JSON.stringify(fields);
var options = JSON.stringify(options);
if (options == '{}') {
result = "db." + col + ".createIndex(" + fields + "); ";
} else {
result = "db." + col + ".createIndex(" + fields + ", " + options + "); ";
}
result = result
.replace(/{"floatApprox":-1,"top":-1,"bottom":-1}/ig, '-1')
.replace(/{"floatApprox":(-?\d+)}/ig, '$1')
.replace(/\{"\$numberLong":"(-?\d+)"\}/ig, '$1');
print(result);
});
});
The above command will output something like the following, based on the amount of collection you have
db.User.createIndex({"createdAt":-1}, {"background":true});
db.User.createIndex({"updatedAt":-1}, {"background":true});
db.Login.createIndex({"loginDate":-1}, {"background":true});
So after executing this, copy the MongoDB queries that are generated above to create the indexes to the new collection, Change the collection name in that then execute it.
For eg: to copy all indexes belonging to the User collection to the UserNew collection, I will rename the query's old collection name to new like the following and execute it, that is it, now you have all the indexes copied to a new collection from the old one.
db.UserNew.createIndex({"createdAt":-1}, {"background":true});
db.UserNew.createIndex({"updatedAt":-1}, {"background":true});
Credits: http://aleksandrmaiorov.com/2019/04/29/mongo-how-to-copy-indexes-from-one-database-to-another/
Thank you for the answer from Rocky and Bloke which helped me a lot
here is the consolidated version as suggested by Bloke.
and in PRODUCTION. we would like to make sure the background: true
is used to avoid slave halt query when indexes creation replicated.
var indexes = db.user.getIndexes();
// we skipped the __id__ indexes and set the default background: true option
indexes.forEach(function(index){
if(index.name =='_id_'){
print("we are skip the _id_ index")
}else{
delete index.v;
delete index.ns;
var key = index.key;
delete index.key
var options = {};
for (var option in index) {
options[option] = index[option]
}
options['background'] = true;
printjson(key);
printjson(options);
db.usertest.createIndex(key, options);
}
});
Rocky Li's answer was helpful but did not create the index options properly at the time of writing (It gathered the option values but not the keys). The following modification worked for me:
var indexes = db.user.getIndexes();
indexes.forEach(function(index){
delete index.v;
delete index.ns;
var key = index.key;
delete index.key
// uncomment if you want to ensure creation is in background
//if(!('background' in index))
//index['background'] = true;
db.user.createIndex(key, index);
});
Copy all indexes from one database another database
use firstDbName;
var indexKeyArray = [];
db.getCollectionNames().forEach(function(collection) {
var indexKeys = db[collection].getIndexKeys();
var base = {};
base["name"] = collection;
base["indices"] = indexKeys
indexKeyArray.push(base);
});
#printjson(indexKeyArray);
use destinationDbName;
indexKeyArray.forEach(function(data) {
db[data.name].createIndexes(data.indices);
});
I have mongo DB and I am using C#.Net to interact with mongo db. C# API has methods for finding a single document and updating it at the same time. For example FindOneAndUpdateAsync.
However I couldn't find any method to find multiple documents and update them at the same time asynchronously.
The code below finding and processing each document asynchronously. How do I also update that document at the same time?
public async Task<IList<IDictionary<string, string>>> DoWork()
{
var collection = _mongoDatabase.GetCollection<BsonDocument>("units");
var filterBuilder = Builders<BsonDocument>.Filter;
var filter = filterBuilder.Ne<string>("status", "INIT") &
(filterBuilder.Exists("isDone", false) |
filterBuilder.Eq<bool>("isDone", false));
// I want to pass this update filter to update the document. But not sure how
var update = Builders<BsonDocument>.Update
.CurrentDate("startTime");
var sort = Builders<BsonDocument>.Sort.Ascending("startTime");
var projection = Builders<BsonDocument>.Projection
.Include("_id")
.Include("fileName"); // for bravity i have removed other projection elements
var output = new List<IDictionary<string, string>>();
// How do i pass update filter and update the document at the same time??
await collection
.Find(filter)
.Sort(sort)
.Project(projection)
.ForEachAsync((unit) =>
{
var dictionary = new Dictionary<string, string>();
Recurse(unit, dictionary);
output.Add(dictionary);
});
return output.Count > 0 ? output : null;
}
That doesn't exist in the mongo .Net api see here.
Just use a combination of Find and UpdateManyAsync.
I have a collection that I'd like to update. The field is given programmatically, so I'd like to do something like this:
var update_string = 'coordinates.lat';
var update = function(value, id, update_string) {
Collection.update({_id:id}, {$set:{update_string:value}})
}
That however does not work and just sets "update_string" to have value {{value}} in the object with _id {{id}} in the Collection. I also tried doing var update_string = "'coordinates.lat'"; to no avail.
How do I accomplish this? Thanks.
You need to set the key in your update $set parameter correctly:
var update = function(value, id, update_string) {
var update_query = {};
update_query[update_string] = value
Collection.update({_id:id}, {$set:update_query})
}
Basically without the modification above, If you used {update_string:value} you would be setting the value of update_string, not coordinates.lat.