Laravel relationship with nested columns? - mongodb

I am using Laravel with mongodb, i have little understanding in laravel eloquent relationship,currently my collection structure is as follows
collection name:general_details
{
"id": 01,
"personal_details":[
[
"emp_id":10,
"blood_group":"B+ve"
],
[
"emp_id":11,
"blood_group":"B+ve"
]
]
}
collection name:employee_details
{
"emp_id":10,
"emp_name":"Alex"
},
{
"emp_id":11,
"emp_name":"Ramesh"
}
i want to create eloquent relationship between two collections for "emp_id", please suggest any solution?

In GenDetails model
public function empdetails(){
return $this->hasOne('App\EmpDetails');
}
In EmpDetails Model
public function genDetails(){
return $this->belongsTo('App\GenDetails');
}
here is one to one relationship between GenDetails and EmpDetails model. So learn more from laravel documentation for Eloquent Relationship.

In GenDetail Model put this relationship
public function empDetails(){
return $this->hasMany('App\EmpDetails','emp_id','personal_details.emp_id');
}
i think this relationship will defiantly work for you.

Related

How to join 3 tables in Mongodb?

Here are 3 entities
ProjectEntity
{_id:String,projectName:String,users:[userEntityId1,userEntityId2]}
UserEntity
{_id:String,userName:String,medias:[mediaEntityId1,mediaEntityId2]}
MediaEntity
{_id:String,url:String}
as description above,I storage foreign id as simple string array to field,I have no idea how to query a result as Json like below:
{
projectName:"demoProject",
users:[
{
userName:"Joey",
medias:[
{url:"https://whatever1.png"},
{url:"https://whatever2.png"},
]
},
{
userName:"Chandler",
medias:[
{url:"https://whatever1.png"},
{url:"https://whatever2.png"},
]
}
]
}
is any goodman can help me? thank you!

Eloquent Model with nested model issue

I have got a couple of tables looking like this:
1) article
id
name
2) article_options
id
article_id
option_id
3) option
id
name
An article can have none, one or many options and I want to return in the RestAPI a JSON structure that looks like this:
[{
"id": 1,
"name": "Article1",
"options": [10]
},
{
"id": 2,
"name": "Article2",
"options": [3, 10]
},
{
"id": 3,
"name": "Article3",
"options": []
}]
whereby 3 and 10 would be the option ids.
I tried a few solutions but none worked. Here is what I currently have:
Article Model:
class Article extends Model
{
# protected $with = ['Article_Option'];
public function options()
{
return $this->hasMany('App\Article_Option');
}
}
Article Controller:
class ArticleController extends Controller
{
public function index()
{
$articles = Article::all();
return response()->json(
$articles
, 200);
}
}
I just can't get my head around how the model and the controller should be configured to achieve this.
Please help.
Thanks
Goppi
[UPDATE]
Thanks to Hides help. With some modification I got it to work the way I wanted. Here is all the code...
Article model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
public function options()
{
return $this->belongsToMany('App\Option');
}
}
ArticleController:
namespace App\Http\Controllers;
use App\Article;
use App\Http\Resources\Article as ArticleResource;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
public function index()
{
$articles = ArticleResource::collection(Article::all());
return response()->json ($articles, 200);
}
}
and the Resource:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Article extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'options' => $this->options->pluck('id')->all()
];
}
}
article_options is your pivot table and the relationship between article and options is a many to many relationship which laravel provides a function for here. So all you will have to do is add the relationship to your article model.
public function options() {
return $this->belongsToMany(Option::class);
}
then when getting the articles you can call that relationship.
$articles = Article::with('options')->get();
This will grab all articles with all option relations and format it in the way that you desired. Laravel can automatically work out which fields it needs to use to form the relationship between the tables so don't worry about that though it does have an option to supply them in the belongsToMany function.
If you are only wanting the id you can pass specific columns to the with function as below.
$articles = Articles::with('options:id')->get()
To then return in a json format you can use resources. Resources help better format the collection of the model which can be used to achieve what you want. You will need to create a resource for articles. In the article resource you can format it how you wanted and to format the options you can use collection methods to transform it into an array of ids by plucking the field from the collection.
Article Resource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'options' => $this->options->pluck('id')->all(),
];
}
So once you have got the articles you can return them like so
return new ArticlesResource::collection($articles);
If later on you can wanting to pass additional columns through for options you can create an options resource and pass that to the options key in you article resource.
'options' => new OptionsResource::collection($this->options)

Compound queries

I have a RESTful service that accepts a custom query, like this:
/entities/User?actions=
{
"$link": {
"entityType": "Manager",
"entity": {
"name": "John Smith"
},
"linkName": "managers",
"backLinkName": "account",
"$set": {
"propertyName": "aclWrite",
"propertyValue": {
"$ref": {
"propertyName": "entityId"
}
}
}
}
}
Which simply means:
Create a new Entity of type User
Create a new Entity of type Manager with the field name, linking the User to be created to this Manager through link name "managers"
Then back-linking the Manager entity to be created to the User with a link name "account" and setting the Manager entity write ACL (Access Control List) to the ID of the User to be created.
I created this query structure because I can't find any suitable Query language that can seem to support such action/procedure.
The question here is are there any Query language that can support such compound action/procedure or can GraphQL handle such?
As a specification, GraphQL doesn't care what fields your schema defines, what arguments those fields take or what your field resolvers do with those arguments. So it's perfectly feasible to design a schema that would let the client compose an equivalent mutation:
mutation {
link(
entityType: "Manager"
entity: {
name: "John Smith"
}
linkName: "managers"
backLinkName: "account"
set: {
propertyName: "aclWrite"
propertyValue: {
ref: {
propertyName: "entityId"
}
}
}
) {
# some fields here to return in the response
}
}
GraphQL does not support references to other nodes inside the same query, so you would still probably want a single mutation whose input mirrored your existing API. That said, using GraphQL for this may still be preferable because of request validation, which is all the more important with complex requests like this. Having an IDE like GraphiQL or GraphQL Playground that lets you write your queries using autocomplete is a big plus too.

Meteorjs - What is the proper way to join collections on backend

I am very new to meteor.js and try to build an application with it. This time I wanted to try it over MEAN stack but at this point I am struggled to understand how to join two collection on server side...
I want very identical behaviour like mongodb populate to fetch some properties of inner document.
Let me tell you about my collection it is something like this
{
name: 'Name',
lastName: 'LastName',
anotherObject: '_id of another object'
}
and another object has some fields
{
neededField1: 'asd',
neededField2: 'zxc',
notNeededField: 'qwe'
}
So whenever I made a REST call to retrieve the first object I want it contains only neededFields of inner object so I need join them at backend but I cannot find a proper way to do it.
So far while searching it I saw some packages here is the list
Meteor Collections Helper
Publish with Relations
Reactive joins in Meteor (article)
Joins in Meteor.js (article)
Meteor Publish Composite
You will find the reywood:publish-composite useful for "joining" related collections even though SQL-like joins are not really practical in Mongo and Meteor. What you'll end up with is the appropriate documents and fields from each collection.
Using myCollection and otherCollection as pseudonyms for your two collections:
Meteor.publishComposite('pseudoJoin', {
find: function() {
return myCollection.find();
},
children: [
{
find: function(doc) {
return otherCollection.find(
{ _id: post.anotherObject },
{ fields: { neededField1: 1, neededField2: 1 } });
}
}
]
});
Note that the _id field of the otherCollection will be included automatically even though it isn't in the list of fields.
Update based on comments
Since you're only looking to return data to a REST call you don't have to worry about cursors or reactivity.
var myArray = myCollection.find().fetch();
var myOtherObject = {};
var joinedArray = myArray.map(function(el){
myOtherObject = otherCollection.findOne({ _id: el.anotherObject });
return {
_id: el._id,
name: el.name,
lastName: el.lastName,
neededField1: myOtherObject.neededField1,
neededField2: myOtherObject.neededField2
}
});
console.log(joinedArray); // These should be the droids you're looking for
This is based on a 1:1 relation. If there are many related objects then you have to repeat the parent object to the number of children.

How to pagination with spring data mongo #DBRef

I want to pagination with Spring Data Mongo.From docs spring data mongo can do :
public interface TwitterRepository extends MongoRepository<Twitter, String> {
List<Twitter> findByNameIn(List<String> names, Pageable pageable);
}
If Twitter Document Object like this:
#Document
public class Twitter {
String name;
#DBRef
List<Comment> comments
}
Does spring data mongo support pagination with comments?
Note: The code specified is not tested, it will just serve as a pointer for you
The following mongo query limits the the array size to be returned:
db.Twitter.find( {}, { comments: { $slice: 6 } } )
The above mechanism can be used to enforce pagination like so:
db.Twitter.find( {}, { comments: { $slice: [skip, limit] } } )
You can try by annotating your method
#Query(value="{ 'name' : {'$in': ?0} }", fields="{ 'comments': { '$slice': [?1,?2] } }")
List<Twitter> findByNameIn(List<String> names, int skip, int limit);
}
You can specify that in your query like so:
Query query = new Query();
query.fields().slice("comments", 1, 1);
mongoTemplate.find(query, DocumentClass.class);
or you can try and execute the command directly using:
mongoTemplate.executeCommand("db.Twitter.find( {}, { comments: { $slice: [skip, limit] } } )")
General Pagination Mechanisms:
General Pagination mechanisms only work at the document level, examples of which are given below.
For them you will have to manually splice the returned comments at the application level.
If you using the MongoTemplate class (Spring-Data Docs) then:
Use org.springframework.data.mongodb.core.query.Query class's skip() and limit() method to perform pagination
Query query = new Query();
query.limit(10);
query.skip(10);
mongoTemplate.find(query, DocumentClass.class);
If you are using Repository (Spring-Data-Reposioty) then use PagingAndSortingRepository