Model relation not working - node.js

I'm am trying to figure out how to make the model relation to work in loopback.
I already managed to make one work (with Country hasMany CountryLanguage), this one shows up in the Countries URL.
But When I tried to do another one it doesn't work.
Here is what I'm trying to do :
I have a User model and an Event model, and I want the Event model to be linked with the users that created the event, but I also want an many-to-many relationship to manage the user's subscription to an event. I already tried the hasMany and it doesnt work, well it doesn't show up in the explorer.
About the ownership relation is it just a Event hasOne User ?
UPDATE :
Here is my relation for the users :
"relations": {
"publicEvents": {
"type": "hasAndBelongsToMany",
"model": "PublicEvent",
"foreignKey": ""
},
"privateEvents": {
"type": "hasAndBelongsToMany",
"model": "PrivateEvent",
"foreignKey": ""
}
},
So now the relation for the event is working as in a User can be an owner of an Event, and I also don't know if I chose the correct relation is hasMany enough in this case? (Also there are no relation declared in the event model)
But know I want also the user to be able to subscribe to an Event, I created two model for this PublicSubscriptions and PrivateSubscriptions in which I put:
"properties": {
"userId": {
"type": "string",
"required": true
},
"privateEventId": {
"type": "string",
"required": true
}
},
But I don't know it this the way to do it, I suppose these fields are not required and relation can work this out for me but I don't know which one to choose.

Rather than creating two models for Event you could have a single Event model, and two relations
relation createdEvents : User hasMany Event
relation subscribedEvents : User hasMany Event
Then, you should have some User with specific custom role ("eventCreator" for instance) for the first relation. Users under this role have more rights (like creating an event).
Standard users will only be able to subscribe. Subscriptions can thus be tracked using the second relation.
Hope this helps

Related

Adding ACL for nested field object in JSON schema object

I am working on specify ACL fields for fields inside objects. I have the validator to check for permission to edit a specific field. For example, the schema looks like this:
"basic_info": {
"properties": {
"cadi_id": {
...
},
"analysis_keywords": {
...
},
"abstract": {
"type": "string",
"title": "Abstract",
"acl": {
"users": ["test#test.org", "test1#test.org"]
}
},
"ana_notes": {
...
},
"conclusion": {
...
}
},
"title": "Basic Information",
"type": "object",
"id": "basic_info",
"required": ["cadi_id"]
}
I have the abstract field with acl. It works fine when the user(not in acl) is editing the abstract field and the validation error is thrown when the user is not in acl.
The problem comes when user(not in acl) is editing other field like conclusion and have the same ValidationError.
When editing any field in basic_info, for example conclusion field, the whole basic_info object is processed in the validator beacuse it's the parent field and now user should be able to edit the conclusion field because there is no acl set. but it gives the ValidationError because we also receive the abstract (which is unchanged) in the basic_info and it goes to validate method and since the user is not in acl it gives ValidationError .
Please let me know what I am missing here to let the user(not in acl) to edit the non acl field?
I tried to get the previous value from the db and check if the controlled field is edited by user or not, but it doesn't seems efficient for this use case and I want to know if there is any native way to do the field level validation. I could not find anything in the docs.

Conditionally update an array in mongoose [duplicate]

Currently I am working on a mobile app. Basically people can post their photos and the followers can like the photos like Instagram. I use mongodb as the database. Like instagram, there might be a lot of likes for a single photos. So using a document for a single "like" with index seems not reasonable because it will waste a lot of memory. However, I'd like a user add a like quickly. So my question is how to model the "like"? Basically the data model is much similar to instagram but using Mongodb.
No matter how you structure your overall document there are basically two things you need. That is basically a property for a "count" and a "list" of those who have already posted their "like" in order to ensure there are no duplicates submitted. Here's a basic structure:
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3")
"photo": "imagename.png",
"likeCount": 0
"likes": []
}
Whatever the case, there is a unique "_id" for your "photo post" and whatever information you want, but then the other fields as mentioned. The "likes" property here is an array, and that is going to hold the unique "_id" values from the "user" objects in your system. So every "user" has their own unique identifier somewhere, either in local storage or OpenId or something, but a unique identifier. I'll stick with ObjectId for the example.
When someone submits a "like" to a post, you want to issue the following update statement:
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
},
{
"$inc": { "likeCount": 1 },
"$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Now the $inc operation there will increase the value of "likeCount" by the number specified, so increase by 1. The $push operation adds the unique identifier for the user to the array in the document for future reference.
The main important thing here is to keep a record of those users who voted and what is happening in the "query" part of the statement. Apart from selecting the document to update by it's own unique "_id", the other important thing is to check that "likes" array to make sure the current voting user is not in there already.
The same is true for the reverse case or "removing" the "like":
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": ObjectId("54bb2244a3a0f26f885be2a4")
},
{
"$inc": { "likeCount": -1 },
"$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
The main important thing here is the query conditions being used to make sure that no document is touched if all conditions are not met. So the count does not increase if the user had already voted or decrease if their vote was not actually present anymore at the time of the update.
Of course it is not practical to read an array with a couple of hundred entries in a document back in any other part of your application. But MongoDB has a very standard way to handle that as well:
db.photos.find(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
},
{
"photo": 1
"likeCount": 1,
"likes": {
"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
}
}
)
This usage of $elemMatch in projection will only return the current user if they are present or just a blank array where they are not. This allows the rest of your application logic to be aware if the current user has already placed a vote or not.
That is the basic technique and may work for you as is, but you should be aware that embedded arrays should not be infinitely extended, and there is also a hard 16MB limit on BSON documents. So the concept is sound, but just cannot be used on it's own if you are expecting 1000's of "like votes" on your content. There is a concept known as "bucketing" which is discussed in some detail in this example for Hybrid Schema design that allows one solution to storing a high volume of "likes". You can look at that to use along with the basic concepts here as a way to do this at volume.

Jhipster display other value when insert connected entites

How to display other value when I want to add new Prelection
But when I have to choose Event, there is Event Id. How to change it to name?
Could you give me an example, what should I do?
This is what you got asked by JHipster entity sub generator when you created Prelection entity and added a relationship to Event:
When you display this relationship with Angular, which field from 'Event' do you want to use? (id)
Just enter the field name from the related entity you want to use for presentation (by default it's "id").
For your existing entity Prelection, you can edit .jhipster/Prelection.json and change otherEntityField:
{
"relationshipName": "event",
"otherEntityName": "event",
"relationshipType": "many-to-one",
"relationshipValidateRules": [
"required"
],
"otherEntityField": "name"
},
and then re-generate your entity with yo jhipster:entity Prelection.

How to populate a non related field mongoose

Document Role =
{ "_id" = "12345",
Name = "Developer"
},
{ "_id" = "67890",
Name = "Manager"
}
Document Employee =
{ "_id" = "00000",
"Name"= "Jack",
"Roles"= [{_id:"12345"},{_id:"67890"}]
}
I want to select one Role and list all the users having the same role
How to do that?
I want to get some thing like.
{ "_id" = "12345",
Name = "Developer"
Employees = [{"_id":"00000"}]
}
Is it possible to use populate to achieve this?
Mongoose .populate() and other methods you might find are not "join magic" for MongoDB. What they in fact all do is execute "additional" query(ies) operations on the database and "merge" the results "under the hood" for your as opposed to you doing the work yourself.
So your best option as long as you can deal with it is to use "embedding" which keeps the "related" information in the document for which you are "pairing" it to, such as for "Roles":
{
"_id": "0000",
"name": "Developer",
"employees": [{ "_id": "12345", "name": "Jack" }]
}
Which is simple, but of course comes at it's own cost and dealing with the "embedded" entries and how you use it according to "updating" or "reading" as is appropriate. It's a single "read" operation, but "updates" may be more costly due to the need to update the embedded information in multiple places, and multiple documents.
If you can "live" with "referencing" and the cost it incurs then you can always do this:
var rolesSchema = Schema({
"name": String,
"emloyees": [{ "type": Schema.Types.ObjectId, "ref": "Employee" }]
});
var employeesSchema = Schema({
"name": String,
"roles": [{ "type": Schema.Types.ObjectId, "ref": "Role" }]
});
var Role = mongoose.model('Role',rolesSchema);
var Employee = mongoose.model('Employee',employeeSchema);
Role.find({ "_id": "12345"}).populate("employees").exec(function(err,docs) {
// populated "joined" results in here
})
What this does behind the scenes is effectively (basic JavaScript representation and "at best") :
var roles = db.role.find({ "_id": "12345" }).map(function(doc) {
doc.employees = doc.employees.map(function(employee) {
return db.employees.find({ "_id": { "$in": doc.employees } }).toArray();
})
})
Mongoose works on the concept of using the "schema" definition to "know" which collection to execute the "other query" on and then return the "joined" results to you. But it is not a single query but multiple hits to the database.
Other schemes might "keep" the referenced collection information in the document itself, as opposed to relying on the "model code" to get that information. But the same principle applies where you need to make another call to the database and perform some type of "merge" in the API provided.
So it all falls down to your choice. Either you "embed" the data and live with that cost, or you "reference" the data and live with the network "cost" that is associated with multiple database hits.
The key point here is "nothing is free", and not even the way that SQL RDBMS perform "joins" which also has a "cost" of it's own and is a lot of the reasoning why NoSQL solutions like MongoDB do it this way and "do not support joins" in a native fashion for the "cost" involved in distributed data systems.
The main lesson here is to "do what suits you and your application", and not just choose the "coolest thing right now", but basically expect what you get from choosing different storage solutions. They all have their own purposes. Horses for Courses as the saying goes.

CouchDB: is it possible to access linked documents inside filter function?

In a contact management app, each user will have his own database. When users wish to share certain categories of contacts with others, a backend will initiate a replication. Each contact is its own document, but also has various children documents such as notes and appointments.
Here is an example...
Contact:
{
"_id": 123,
"type": "contact",
"owner": "jimmy",
"category": "customer",
"name": "Bob Jones",
"email": "bob#example.com"
}
Note:
{
"_id": 456,
"type": "note",
"owner": "jimmy",
"contact_id": 123,
"timestamp": 1383919278,
"content": "This is a note about Bob Jones"
}
So let's say Jimmy wants to share his only his customers with sales manager Kevin, while his personal contacts remain private. When the note passes through the replication filter, is it possible to access the linked contact's category field?
Or do I have to duplicate the category field in every single child of a contact? I would prefer not to have to do this, as each contact may have many children which I would have to update manually every time the category changes.
Here is some pseudo-code for the filter function:
function(doc, req)
{
if(doc.type == “contact”) {
if(doc.category == req.query.category) {
return true;
}
}
else if(doc.contact_id) {
if(doc.contact.category == req.query.category) {
return true;
}
}
return false;
}
If this is possible, please describe how to do it. Thanks!
There are some other options.
There's a not-so-well-known JOIN trick in CouchDB. Instead of using replication, however, you'll have to share the results of a MapReduce View -- unfortunately you can use a view as a filter for replication. If you're using Cloudant (disclaimer: I'm employed by Cloudant) you can use chained-MapReduce to output the result to another database that you could then replication from...
Additionally, I think this SO post/answer on document structures and this join trick could be helpful: Modeling relationships on CouchDB between documents?
No, this is not possible. Each document must be consistent so it has no any explicit relations with others documents. Having contact_id value as reference is just an agreement from your side - CouchDB isn't aware about this.
You need to literally have category document be nested within contact one to do such trick e.g. have single document to process by filter function. This is good solution from point when you need to have consistent state of contact document.

Resources