saving data to firebase with angularfire2 - Ionic - object

I am trying to upload an object to firebase, the problem is with storing the entire object in the database - only one of the properties is being stored, here it is:
constructor(af: AngularFireDatabase ...) {
this.items = this.af.list('/appointments/' + this.username);
}
logForm() { //executed on a form submit
this.items.push({day:{date:this.selectedDate, reserved:this.appointments}});
}
this.items is a FirebaseListObservable and everything works fine with that - when this push is successful, here is what is in the database:
As you can see, there is no date property in the database, only reserved (which is an array of strings), why isn't the date getting stored? I am new to firebase's take on NoSQL - am I breaking a rule? Thanks.

I figured it out - the object has to look like this:
{date:{day:this.selectedDate.toString()}, reserved:{appointment:this.appointments}}

Related

Trying to get data from another table, snapshot is null

I'm trying to get data from another table using a cloud function and it's telling me the snapshot is null.
I have a Firebase database that I have some IoT devices connected to. They update their respective tables(I hope that's the right word) in the database (device_001, device_002, device_003) and send on to the external API I am using, that works which are great.
Now I need to get the devices to look up where they are, I have set up another table which each contain their id, location, and timestamp.
Lookup table structure:
devices
device_001
id: ...
location: ...
timestamp: ...
Code:
exports.devices_Listener = functions.database.ref('/devices/{deviceId}/{entryId}').onWrite(snapshot => {
object = snapshot.after.val();
getCurrentLocation();
process();
return null
})
function getCurrentLocation() { functions.database.ref('locations/{deviceId}').limitToLast(1).once('value').then(function(snapshot) {
var o = snapshot.val();
})
}
I expected this to get the snapshot and allow me to get the location so I can store it with the processed data (that's all working so not included here).
When I try to get the location field I get can't read the property 'location'
and when I try to just log the snapshot to the console it tells me it is null.
I can't see what I've done wrong here but I'm sure it's small and simple.
Thanks for taking the time to read this nonsensical mess.

MongoDB update object and remove properties?

I have been searching for hours, but I cannot find anything about this.
Situation:
Backend, existing of NodeJS + Express + Mongoose (+ MongoDB ofcourse).
Frontend retrieves object from the Backend.
Frontend makes some changes (adds/updates/removes some attributes).
Now I use mongoose: PersonModel.findByIdAndUpdate(id, updatedPersonObject);
Result: added properties are added. Updated properties are updated. Removed properties... are still there!
Now I've been searching for an elegant way to solve this, but the best I could come up with is something like:
var properties = Object.keys(PersonModel.schema.paths);
for (var i = 0, len = properties.length; i < len; i++) {
// explicitly remove values that are not in the update
var property = properties[i];
if (typeof(updatedPersonObject[property]) === 'undefined') {
// Mongoose does not like it if I remove the _id property
if (property !== '_id') {
oldPersonDocument[property] = undefined;
}
}
}
oldPersonDocument.save(function() {
PersonModel.findByIdAndUpdate(id, updatedPersonObject);
});
(I did not even include trivial code to fetch the old document).
I have to write this for every Object I want to update. I find it hard to believe that this is the best way to handle this. Any suggestions anyone?
Edit:
Another workaround I found: to unset a value in MongoDB you have to set it to undefined.
If I set this value in the frontend, it is lost in the REST-call. So I set it to null in the frontend, and then in the backend I convert all null-values to undefined.
Still ugly though. There must be a better way.
You could use replaceOne() if you want to know how many documents matched your filter condition and how many were changed (I believe it only changes one document, so this may not be useful to know). Docs: https://mongoosejs.com/docs/api/model.html#model_Model.replaceOne
Or you could use findOneAndReplace if you want to see the document. I don't know if it is the old doc or the new doc that is passed to the callback; the docs say Finds a matching document, replaces it with the provided doc, and passes the returned doc to the callback., but you could test that on your own. Docs: https://mongoosejs.com/docs/api.html#model_Model.findOneAndReplace
So, instead of:
PersonModel.findByIdAndUpdate(id, updatedPersonObject);, you could do:
PersonModel.replaceOne({ _id: id }, updatedPersonObject);
As long as you have all the properties you want on the object you will use to replace the old doc, you should be good to go.
Also really struggling with this but I don't think your solution is too bad. Our setup is frontend -> update function backend -> sanitize users input -> save in db. For the sanitization part, we use a helper function where we integrate your approach.
private static patchModel(dbDocToUpdate: IModel, dataFromUser: Record<string, any>): IModel {
const sanitized = {};
const properties = Object.keys(PersonModel.schema.paths);
for (const key of properties) {
if (key in dbDocToUpdate) {
sanitized[key] = data[key];
}
}
Object.assign(dbDocToUpdate, sanitized);
return dbDocToUpdate;
}
That works smoothly and sets the values to undefined. Hence, they get removed from the document in the db.
The only problem that remains for us is that we wanted to allow partial updates. With that solution that's not possible and you always have to send everything to the backend.
EDIT
Another workaround we found is setting the property to an empty string in the frontend. Mongo then also removes the property in the database

Orchard background task not persisting PartRecords to the database

I'm trying to use a background task to gather Likes/Comments from the Facebook Graph APi and use that to drive our blog's trending.
Here the trendingModels have already been populated and are being used to fill in the TrendingParts.GraphId and TrendingParts.TrendingValue.
I'm not getting any exceptions and the properties on TrendingPart point to the fields in the TrendingPartRecord.
Yet nothing persists to the database, any ideas why?
_orchardsServices is IOrchardServices
var articleParts = _orchardService.ContentManager.GetMany<TrendingPart>(
trendingModels.Select(r => r.OrchardId).ToList(),
VersionOptions.Published,
QueryHints.Empty);
// Cycle through the records and update them from the matching model
foreach (var articlePart in articleParts)
{
ArticleTrendingModel trendingModel = trendingModels.Where(r => r.OrchardId == articlePart.Id).FirstOrDefault();
if(trendingModel != null)
{
// Not persisting to the database, WHY?
// What's missing?
// If I'm understanding things properly nHibernate should push this to the db autoMagically.
articlePart.GraphId = trendingModel.GraphId;
articlePart.TrendingValue = trendingModel.TrendingValue;
}
}
Edit:
It's probably worth noting that I can update and publish the fields on the TrendingPart in the admin panel but the saved changes don't appear in the MyModule_TrendingPartRecord table.
The solution was to change my Service to a transient dependency using ITransientDependency.
The service was holding a reference to the PartRecords array and because it was treated as a Singleton it never disposed and the push to the database was never made.

Inserting a variable as a key in MongoDB

I am retrieving JSON data from an API and this is a short example of it:
{"hatenames":
{"id":6239,
"name":"hatenames",
"stat1":659,
"stat2":30,
"stat3":1414693
}
}
I am trying to insert it in the MongoDB (using MongoClient) but it won't let me put just the object directly or use a variable as a field name. If I put the var username it will just output it as username in the database field. This is what I would like to work:
collection.insert({object}
collection.insert({username:object[username]}
but it doesn't and I've been stuck on this for the past few hours. The only resolution I found was to set it and then update the field name afterwards, but that just seems lame to have to do every single time, is there no elegant or easy option that I am somehow missing?
First of all, being a programmer, you should forget about "it does not work" phrase. You should describe how it does not work with exact error messages you encounter. Not to your problem.
Just because I can easily do
db.coll.insert({"hatenames":
{"id":6239,
"name":"hatenames",
"stat1":659,
"stat2":30,
"stat3":1414693
}
})
or var a = {"hatenames":{"id":6239, "name":"hatenames", "stat1":659, "stat2":30, "stat3":1414693}}; and db.coll.insert(a),
I think that the problem is that your object is not really an object, but a string. So I suspect that you have a string returned to you back from that API. Something like '{"hatenames":{...}' and this caused a problem when you try to save it or access the properties. So try to convert it to JSON.
Try doing this:
MongoClient.connect('mongodb://127.0.0.1:27017/db_name', function(err, db) {
if(err) throw err;
someCollection = db.collection('some_collection');
});
someCollection.insert({
name: hatenames['name']
});
EDIT
For Dynamic approach, I would suggest you to play aroung this function:
Object.keys(hatenames)
this function will return keys in array.
EDIT 2
I have founded a link: Insert json file into mongodb using a variable
See, if that helps.

How to display arbitrary, schemaless data in HTML with node.js / mongodb

I'm using mongodb to store application error logs as json documents. I want to be able to format the error logs as HTML rather than returning the plain json to the browser. The logs are properly schemaless - they could change at any time, so it's no use trying to do this (in Jade):
- var items = jsonResults
- each item in items
h3 Server alias: #{item.ServerAlias}
p UUID: #{item.UUID}
p Stack trace: #{item.StackTrace}
h3 Session: #{item.Session}
p URL token: #{item.Session.UrlToken}
p Session messages: #{item.Session.SessionMessages}
as I don't know what's actually going to be in the JSON structure ahead of time. What I want is surely possible, though? Everything I'm reading says that the schema isn't enforced by the database but that your view code will outline your schema anyway - but we've got hundreds of possible fields that could be removed or added at any time so managing the views in this way is fairly unmanageable.
What am I missing? Am I making the wrong assumptions about the technology? Going at this the wrong way?
Edited with extra info following comments:
The json docs look something like this
{
"ServerAlias":"GBIZ-WEB",
"Session":{
"urltoken":"CFID=10989&CFTOKEN=f07fe950-53926E3B-F33A-093D-3FCEFB&jsessionid=84303d29a229d1",
"captcha":{
},
"sessionmessages":{
},
"sessionid":"84197a667053f63433672873j377e7d379101"
},
"UUID":"53934LBB-DB8F-79T6-C03937JD84HB864A338",
"Template":"\/home\/vagrant\/dev\/websites\/g-bis\/code\/webroot\/page\/home\/home.cfm, line 3",
"Error":{
"GeneratedContent":"",
"Mailto":"",
"RootCause":{
"Message":"Unknown tag: cfincflude.",
"tagName":"cfincflude",
"TagContext":[
{
"RAW_TRACE":"\tat cfhome2ecfm1296628853.runPage(\/home\/vagrant\/dev\/websites\/nig-bis\/code\/webroot\/page\/home\/home.cfm:3)",
"ID":"CFINCLUDE",
"TEMPLATE":"\/home\/vagrant\/dev\/websites\/nig-bis\/code\/webroot\/page\/home\/home.cfm",
"LINE":3,
"TYPE":"CFML",
"COLUMN":0
},
{
"RAW_TRACE":"\tat cfdisplay2ecfm1093821753.runPage(\/home\/vagrant\/dev\/websites\/nig-bis\/code\/webroot\/page\/display.cfm:6)",
"ID":"CFINCLUDE",
"TEMPLATE":"\/home\/vagrant\/dev\/websites\/nig-bis\/code\/webroot\/page\/display.cfm",
"LINE":6,
"TYPE":"CFML",
"COLUMN":0
}
]
}
}
... etc, but is likely to change depending on what the individual project that generates the log is configured to trigger.
What I want to end up with is a formatted HTML page with headers for each parent and the children listed below, iterating right through the data structure. The Jade sample above is effectively what we need to output, but without hard-coding that in the view.
Mike's analysis in the comments of the problem being that of creating a table-like structure from a bunch of collections that haven't really got a lot in common is bang-on. The data is relational, but only within individual documents - so hard-coding the schema into anything is virtually impossible as it requires you to know what the data structure looks like first.
The basic idea is what #Gates VP described. I use underscore.js to iterate through the arrays/objects.
function formatLog(obj){
var log = "";
_.each(obj, function(val, key){
if(typeof(val) === "object" || typeof(val) === "array"){
// if we have a new list
log += "<ul>";
log += formatLog(val);
log += "</ul>";
}
else{
// if we are at an endpoint
log += "<li>";
log += (key + ": " + val);
log += "</li>";
}
});
return log;
}
If you call formatLog()on the example data you gave it returns
ServerAlias: GBIZ-WEBurltoken: CFID=10989&CFTOKEN=f07fe950-53926E3B-F33A-093D-3FCEFB&jsessionid=84303d29a229d1sessionid: 84197a667053f63433672873j377e7d379101UUID: 53934LBB-DB8F-79T6-C03937JD84HB864A338Template: /home/vagrant/dev/websites/g-bis/code/webroot/page/home/home.cfm, line 3GeneratedContent: Mailto: Message: Unknown tag: cfincflude.tagName: cfincfludeRAW_TRACE: at cfhome2ecfm1296628853.runPage(/home/vagrant/dev/websites/nig-bis/code/webroot/page/home/home.cfm:3)ID: CFINCLUDETEMPLATE: /home/vagrant/dev/websites/nig-bis/code/webroot/page/home/home.cfmLINE: 3TYPE: CFMLCOLUMN: 0RAW_TRACE: at cfdisplay2ecfm1093821753.runPage(/home/vagrant/dev/websites/nig-bis/code/webroot/page/display.cfm:6)ID: CFINCLUDETEMPLATE: /home/vagrant/dev/websites/nig-bis/code/webroot/page/display.cfmLINE: 6TYPE: CFMLCOLUMN: 0
How to format it then is up to you.
This is basically a recursive for loop.
To do this with Jade you will need to use mixins so that you can print nested objects by calling the mixin with a deeper level of indentation.
Note that this whole thing is a little ugly as you won't get guaranteed ordering of fields and you may have to implement some logic to differentiate looping on arrays vs. looping on JSON objects.
You can try util.inspect. In your template:
pre
= util.inspect(jsonResults)

Resources