Is it possible to change Firebase path from an object? - firebase

I'm trying to make a very simple thing, something like:
root: {
objects: {
id_subobj1: { // these are two objects doing current events.
name: "subName1",
description: "it's nice"
},
id_subobj2: {
name: "subName2",
description: "it's cool"
}
},
history: {
// once they are done, I'd like to store them in this branch as an exact copy as they were in the "Objects" branch.
id_subobj: {
name: "name",
description: "it was nice"
}
}
}
What I want to achieve is to get my objects, and something like copy and paste them into the history branch.
I'm trying to do so, but I had no success of doing that.
Any ideas?

Related

Firebase Database Design

I have a database containing a structure similar to the one shown below. Since I am not allowed to make it public I am using the following keys:
i = {0,1,2,3....}
All a(i) represent single key/value pairings e.g. userName: "awesome"
With the below structure, every time a User wants to create new Stuff these are the steps I currently take
Store images to FIRStorage and retrieve their respective downloadURL
Then I add the Stuff to FIRDatabase. At this point I add all of the info related to a(i) because they're all under a single child; Stuff.UUID, hence I send one huge dictionary consisting of the data.
The issue arises in adding data to the mini-dictionaries. Because they are in different paths, I have to individually make requests to all of them as shown below
I then add location info
Followed by the respective child of timeStamp
The images information is next to be updated
Subscribe the User to respective Stuff.UUID
Lastly add the User.UUID to the members portion of Stuff
Is it possible to reduce steps 3-7?
As a follow up, is it possible to add values into different paths with one call?
PS: Link to what the code of the above demo might look like. Due to confidentiality stuff I am not allowed to post the actual code.
{
"Users":
{
"JglJnGDXcqLq6m844pZ":
{
a(0),
a(1),
a(2),
a(3),
a(4),
a(5),
"Stuff":
{
"fcWpzduhpPn8XR6Zqca": true,
"gfntTr6TkDwZ439jkW8": true
}
}
},
"Stuff":
{
"fcWpzduhpPn8XR6Zqca":
{
a(0),
a(1),
a(2),
a(3),
a(4),
a(5),
a(6),
a(7),
"location":
{
"latitude":"-17.41439",
"longitude":"-5.85170"
},
"timestamp":
{
"created":
{
a(0),
a(1),
a(2),
a(3),
a(4),
a(5),
},
"lastModified":
{
a(0),
a(1),
a(2),
a(3),
a(4),
a(5),
}
},
"images":
{
"B4FaR6wfJAeXqJ29T33":
{
"imageURL": "https://google.com"
}
},
"members":
{
"JglJnGDXcqLq6m844pZ": true,
"DpHAfrqL4eqbR8QNgHg": true
}
}
}
}

Difficulty setting up validation rules for Firebase datastructure

I'm working on setting up validaton rules for a Firebase data structure, created using the Bolt compiler.
I'm currently having the Bolt statement below:
path /sharedEvents/{share} is Boolean[] {
read() { isMailOfCurrentUser( share ) }
create() { isOwnerOfEvent( ...) } //NOT YET CORRECT!
delete() { isOwnerOfEvent( prior(...) } //NOT YET CORRECT!
}
With this, I'm trying to achieve that:
Only users having a mail corresponding to the key of 'share' are allowed to read the data (they use this date to retrieve the key of events shared with them.
Only the owner of an event is able to add/remove the key for his event to the list of shared events.
This second point is where I'm running into trouble -I'm not able to create the create/delete rules- since I have no idea how to reference the keys of the boolean values in the validation rule...
Example data in Firebase for the above bolt statement:
sharedEvents
ZW5kc3dhc0BldmVyeW1hMWwuYml6
-BDKBEvy-hssDhKqVF5w: true
-FDKBEvy-hsDsgsdsf5w: true
-ADBEvy-hfsdsdKqVF5w: true
aXQnc251bWJlcnNAbWExbDJ1LnVz
-KBEvy-hsDhH6OKqVF5w: true
To clarify the needs on this example:
Only user with mail 'ZW5kc3dhc0BldmVyeW1hMWwuYml6' is able to read the three nested childs.
Only the owner of event '-BDKBEvy-hssDhKqVF5w' should be able to create/delete this value. (the same for the other event key/boolean pairs).
My question: is this setup going to work (and how to setup the create/delete rules)? Or is this not going to work and should I rethink/structure the data?
Any help is appreciated!
-----------------OUTPUT JSON FILE------------------------------------------
The question above has been answered, this section is showing the resulting json
"sharedEvents": {
"$share": {
".read": "<removed for readability>",
"$event": {
".validate": "newData.isBoolean()",
".write": "<removed for readability>"
}
}
},
Thanks again for your quick support!
You'll need a nested path statement to handle the restriction on the events (the nodes under /sharedEvents/$mail/$eventid). I quickly prototyped with this JSON structure:
{
"events": {
"-ADBEvy-hfsdsdKqVF5w": {
"name": "Event 1",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-BDKBEvy-hssDhKqVF5w": {
"name": "Event 2",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-FDKBEvy-hsDsgsdsf5w": {
"name": "Event 3",
"ownerMail": "aXQnc251bWJlcnNAbWExbDJ1LnVz"
},
"-KBEvy-hsDhH6OKqVF5w": {
"name": "Event 3",
"ownerMail": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
},
"sharedEvents": {
"ZW5kc3dhc0BldmVyeW1hMWwuYml6": {
"-ADBEvy-hfsdsdKqVF5w": true,
"-BDKBEvy-hssDhKqVF5w": true,
"-FDKBEvy-hsDsgsdsf5w": true
},
"aXQnc251bWJlcnNAbWExbDJ1LnVz": {
"-KBEvy-hsDhH6OKqVF5w": true
}
},
"userMails": {
"peter": "aXQnc251bWJlcnNAbWExbDJ1LnVz",
"puf": "ZW5kc3dhc0BldmVyeW1hMWwuYml6"
}
}
And came up with these rules:
path /sharedEvents/{share} {
read() { isMailOfCurrentUser(share) }
}
path /sharedEvents/{share}/{event} is Boolean {
create() { isOwnerOfEvent(event) }
delete() { isOwnerOfEvent(prior(event)) }
}
isMailOfCurrentUser(share) { true }
getMailOfCurrentUser(uid) { root.ownerMails.uid }
getEventOwnerMail(event) { root.events.event.ownerMail }
isOwnerOfEvent(event) { getMailOfCurrentUser(auth.uid) == getEventOwnerMail(event) }
Ignoring any mistakes on my end, this should be the basics of the authorization structure you're looking for.

Collection2 relationship error due to missing collection object

I am attempting to create a relationship between 2 collections, but one of the collections is not available to be referenced in the other. Specifically, I have 2 collections: Sites and ContentTypes. This is what they include:
// app/lib/collections/sites.js
Sites = new Mongo.Collection('sites');
Sites.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Name",
max: 100
},
client: {
type: String,
label: "Client",
max: 100
},
created: {
type: Date,
autoValue: function() {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset(); // Prevent user from supplying their own value
}
}
}
}));
And here's the ContentTypes collection:
// app/lib/collections/content_types.js
ContentTypes = new Mongo.Collection('content_types');
ContentTypes.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Name",
max: 100
},
machineName: {
type: String,
label: "Machine Name",
max: 100
},
site:{
type: Sites
},
created: {
type: Date,
autoValue: function() {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset(); // Prevent user from supplying their own value
}
}
}
}));
When I add the Sites reference to the ContentTypes schema, I the app crashes with the error:
ReferenceError: Sites is not defined
at lib/collections/content_types.js:32:11
I haven't had much luck finding documentation for relationships in collection2 beyond this. It looks like the format referenced there is supposed to work based on this thread.
This is due to the order Meteor loads files. See section on File Load Order here:
There are several load ordering rules. They are applied sequentially to all applicable files in the application, in the priority given below:
HTML template files are always loaded before everything else
Files beginning with main. are loaded last
Files inside any lib/ directory are loaded next
Files with deeper paths are loaded next
Files are then loaded in alphabetical order of the entire path
e.g. rename app/lib/collections/sites.js to app/lib/collections/a_sites.js and the Sites variable will be defined when the content_types.js file is being loaded.

How to generate a form to select a user using Autoform and Collection2 in Meteor?

I want to be able to select several users from a list of users.
I am user collection2, simple-schema and autoform.
I'd like to generate a simple quickForm for doing this. Here's my simple-schema:
Schemas.Item = new SimpleSchema({
name: {
type: String,
label: "Name",
max: 100
},
userIds: {
type: [String],
regEx: SimpleSchema.RegEx.Id
}
});
Looking at the autoform docs, I noticed that I want to have a select view so I need to pass in options.
I'd like to be able to do this right in my schema!
userIds: {
type: [String],
regEx: SimpleSchema.RegEx.Id
options: function() {
// return users with {value:_id, label:username}
}
}
Otherwise, I'd have to generate a template with quickFormFields just to pass in the options.
Just to pile things on, there shouldn't be any duplicate userIds...
Thanks for any help
Probably you have already found an answer, but maybe somebody will find it useful. I have lots of different things to specify once you select user, that's why my type for users is [Object]. In your case, you can modify that. The most important part is autoform.options method and seems to be the part you were looking for.
users: {
type: [Object]
},
"users.$.id": {
// you can use your own type, e.g. SimpleSchema.RegEx.Id, as I am using custom Schema for accounts
type: Schemas.Account._id,
label: 'Select user',
autoform: {
options: function () {
var options = [];
Meteor.users.find().forEach(function (element) {
options.push({
label: element.username, value: element._id
})
});
return options;
}
}
}
Snippet above will give you the list of all the users so you can easily select them from dropdown list.
Remember to add appropriate publish method to make that working as without that you will always get only currently logged one.

CouchDB view documents with tag=foo or tag=bar

Given my following documents:
{
_id: ###,
type: "blogpost",
title: "First blog post",
tag: "tutorial"
}
{
_id: ###,
type: "blogpost",
title: "Second blog post",
tag: "report"
}
{
_id: ###,
type: "blogpost",
title: "Third blog post",
tag: "tutorial"
}
{
_id: ###,
type: "blogpost",
title: "Fourth blog post",
tag: "article"
}
Now, what I would like to do is: Find all blogposts which tag is article or report.
I already read in the documentation that I am able to perform a POST to a view or list, allowing for searching multiple keys. But this will always need cURL or something right?
In case you need to specify article,report as variable in your HTTP call, then all you need is a view and a list
View: test_view
function(doc) {
if (doc.tag) {
emit(doc.tag, doc);
}
};
List: test_list
function(head, req) {
start({
"headers": {
"Content-Type": "text/html"
}
});
var row;
var tags = req.query.tags;
var tagArray = tags.split(',');
while(row = getRow()) {
if (tagArray.indexOf(row.key) != -1) {
send(row.value.tag + ' : ' + row.value.title + '<br>');
}
}
}
Now, you can get the list/html with
http://yourserver.com:5985/db/_design/test/_list/test_list/test_view?tags=article,report
You're going to need to create at least one view to make this work. I don't have a good idea of your needs so I'll just do a simple example without thought to it being the best way to implement what you want.
Visit Futon at http://yourserver.com:5984/_utils, and create a view in your database. You'll only need a map function to accomplish what you're asking for:
function(doc) {
if (doc.tag && (doc.tag == "article" || doc.tag == "report")) {
emit(doc.tag, doc);
}
}
If you save your view and call it articles_or_reports, you can get the data from your view with this request:
http://yourserver.com:5984/db/_design/test/_view/articles_or_reports
Which will return
{"total_rows":2,"offset":0,"rows":[
{"id":"168ba21f7209994b69336dd8c30041f3","key":"article","value":{"_id":"168ba21f7209994b69336dd8c30041f3","_rev":"1-f033b30522d09c33cbd68332b89c95a7","type":"blogpost","title":"Fourth blog post","tag":"article"}},
{"id":"168ba21f7209994b69336dd8c3003139","key":"report","value":{"_id":"168ba21f7209994b69336dd8c3003139","_rev":"1-f7a473afc253972f7cfec62a335dcb23","type":"blogpost","title":"Second blog post","tag":"report"}}
]}
But this will always need cURL or something right?
It depends on your application, but the only interface to CouchDB is through HTTP. There are libraries for many languages to bring your interactions to a higher level.

Resources