Laravel permission get user roles as object instead of array - eloquent

Currently using spatie/laravel-permission package to manage user roles: an user could have a single role.
return $this->userModel
->select('id', 'first_name', 'last_name', 'email', 'slug')
->with(['roles' => function ($query) {
$query->select('name', 'guard_name');
}])
->find($id);
Hoever, when I'm running the following query, it returns an array of roles.
"roles": [
{
"name": "personal_trainer",
"pivot": {
"model_id": "9e8fb1a1-e725-4b48-befa-d9c4783c9eda",
"role_id": 2,
"model_type": "App\\Models\\User\\User"
}
}
],
How can I make "roles" key return a single object instead of an array? I want to avoid manipulating it post-query.

Kindly try
return $this->userModel
->select('id', 'first_name', 'last_name', 'email', 'slug')
->with(['roles' => function ($query) {
$query->select('name', 'guard_name');
}])
->first();

Related

Return document with all array of objects where element exists

I'm trying to return one document with an array of objects where userAnswer exists. My query below returns only the first object with the array. What am I missing here? It should return two.
Meteor and MongoDB being used.
MongoDB: document
{
_id: 1,
questions: [
{ question: 'test question', userAnswer: 'answer' },
{ question: 'test question two', userAnswer: 'answertwo' },
{ question: 'test question three' }
]
};
Mongodb: Query
ConductedExams.findOne(
{
userId,
examId,
userCompletedExam: null
},
{ fields: { questions: { $elemMatch: { userAnswer: { $exists: true } } } } }
);
"findOne" return only one element.
You should use "find".

Laravel Mongodb Messenger relations data not filtering

I have 3 collection instances with belongsToMany relations.
I want to filter data from all 3 collections but not sure how.
Collection Structure.
Payment:
{
"_id": "5ba3c8f7c2ab9b3bed20ae22",
"code": "GHFH",
"amount": "345.00"
}
User:
{
"_id": "5ba3c87cc2ab9b34be139382",
"name": "Jack",
"email": "Pd#gmail.com",
"payment_ids": [
"5ba3c8f7c2ab9b3bed20ae22"
]
}
Customer:
{
"_id": "23c34c87cc2ab9b34b3423423",
"name": "cfb",
"email": "Psfsdd#gmail.com",
"payment_ids": [
"5ba3c8f7c2ab9b3bed20ae22"
]
}
I have create below query.
$cruds = payment::with([
'user' => function ($query) {
$query->orWhere('name','like', "%'".$search."'%");
},
'customer' => function ($query) {
$query->orWhere('name','like', "%'".$search."'%");
}
])
->orWhere('code','like', "%'".$search."'%")
->orWhere('amount', 'like', "%'".$search."'%")
->offset($start)
->limit($limit)
->orderBy($order, $dir)
->get();
Please Suggest.
I have change in query.
$cruds = payment::with([
'user' => function ($query) {
$query->where('name','like', "%{$search}%");
},
'customer' => function ($query) {
$query->where('name','like', "%{$search}%");
}
])
->where('code','like', "%{$search}%")
->where('amount', 'like', "%{$search}%")
->offset($start)
->limit($limit)
->orderBy($order, $dir)
->get();

Updating a particular sub document in mongo db php

I have a collection in mongo db called EmployeeTbl with document like
{
"_id": ObjectId("5a8d47d8d2ccda11fc004d91"),
"EmployeeNumber": "9883456787",
"FirstName": "Sana",
...
"ContactDetails": [
{
"ContactTypeId": "04596c6f-82e6-8f00-e3a9-1f3199894284",
"ContactType": "Phone",
"ContactTypeValue": "99456789756"
},
{
"ContactTypeId": "71d0152c-293f-4c6f-2360-bbdfe368eacb",
"ContactType": "Phone",
"ContactTypeValue": "9894567890"
}
]
}
I am trying to update a sub document inside ContactDetails and I have written below code. It is not updating the existing one. Instead of updating, it adds new sub document.
Please help me !!!
public function updateContactDetailsForItsSubDocument()
{
// $bulkbatch = new MongoDB\Driver\BulkWrite(['ordered' => true]);
$subDocumentContactDetails = array(
"ContactDetails" =>
array(
"ContactType" => $this->ContactType,
"ContactTypeValue" => $this->ContactTypeValue
)
);
$this->collection->update(
array('_id' => new MongoDB\BSON\ObjectID($this->id), 'ContactDetails.ContactTypeId'=> $this->ContactTypeId),
array('$set' => $subDocumentContactDetails)
);
// $this->manager->executeBulkWrite($this->collection, $bulkbatch);
}
Change your $subDocumentContactDetails variable so that it uses the $ positional operator for updating an embedded document:
$subDocumentContactDetails = array(
"ContactDetails.$.ContactType" => $this->ContactType,
"ContactDetails.$.ContactTypeValue" => $this->ContactTypeValue
);
$this->collection->update(
array(
"_id" => new MongoDB\BSON\ObjectID($this->id),
"ContactDetails.ContactTypeId" => $this->ContactTypeId
),
array("$set" => $subDocumentContactDetails)
);

How to do mongo db aggregation join operation in php?

I have three collections in mongodb like
employeeTitleTbl contains
{
"_id": ObjectId("5a7c2027d2ccda04d0006070"),
"EmployeeTitleName": "Librarian",
"EmployeeTitleCode": "ji8766",
..
}
DepartmentsTbl contains
{
"_id": ObjectId("5a817402d2ccda13240015a5"),
"DepartmentCode": "149",
"DepartmentName": "Biology",
..
}
EmployeesTbl contains
{
"_id": ObjectId("5a81957bd2ccda13240015a8"),
"EmployeeNumber": "25789998",
"JobTitle": ObjectId("5a7c2008d2ccda04d000606f"),
"Department": ObjectId("5a8173e6d2ccda13240015a4"),
...
}
I am very new to mongodb and also driver has also updated 3.6, so it is very difficult to find the latest method of aggregation in php. So I was tweaking the below code for adding department and employee title actual values like "EmployeeTitleName" and "DepartmentName" in EmployeesTbl.
public function fetchAll()
{
$pipeline = array(
array(
'$lookup' => array(
'from' => 'DepartmentsTbl',
'localField' => 'Department',
'foreignField' => '_id',
'as' => 'DepartmentDetails'
)
),
array(
'$lookup' => array(
'from' => 'employeeTitleTbl',
'localField' => 'JobTitle',
'foreignField' => '_id',
'as' => 'JobTitleDetails'
)
),
);
try
{
$cursor = $this->db->EmployeesTbl->aggregate($pipeline);
}
catch(Exception $e){
}
return $cursor->toArray();
}
Please help me in latest method!!!
The output is like
array(2) { [0]=> object(MongoDB\Model\BSONDocument)#29 (1) { ["storage":"ArrayObject":private]=> array(25) { ["_id"]=> object(MongoDB\BSON\ObjectId)#10 (1) { ["oid"]=> string(24) "5a8176c0d2ccda13240015a6" } ["EmployeeNumber"]=> string(8) "25799989"....
...........
["DepartmentDetails"]=> object(MongoDB\Model\BSONArray)#27 (1) { ["storage":"ArrayObject":private]=> array(0) { } } ["JobTitleDetails"]=> object(MongoDB\Model\BSONArray)#28 (1) { ["storage":"ArrayObject":private]=> array(0) { } } } } [1]=.........
You need to use $lookup to join 2 or more tables for example..
db.employeeTitle.aggregate([{
$lookup: {
from: 'employees',
localField: 'EmployeeTitleName',
foreignField: '_id',
as: 'employeeData'
}
},
{ $unwind: '$employeeData' },
{
$project: { profile: '$employeeData' }
}
])
It joins two tables employeeTitle and employees and give you full information about employees.

Extjs5 bound tagfield

I have two entities, User and Role both with manyToMany association to each other.
Then I have a grid displaying the list of users and on the rightside a form with user details including a tagfield which will show and allow select roles for the user.
If the binding for the tagfield is set as
bind: {
store: '{roles}',
value: '{mainGrid.selection.roles}'
}
then it don't show the roles that the user already has and throws:
"Uncaught TypeError: parentData[association.setterName] is not a function"
when one tries to set the user roles
So I've also tried to bind the tagfield value to a formula like
bind: {
store: '{roles}',
value: '{userRoles}'
}
and the tagfield shows the roles of the selected user but I don't know how to set the selected roles back to the user entity.
My models are:
Ext.define('App.model.security.User', {
extend: 'App.model.Base',
entityName: 'User',
fields: [
{ name: 'id' },
{ name: 'email'},
{ name: 'name'},
{ name: 'enabled', type: 'bool'}
],
manyToMany: {
UserRoles: {
type: 'Role',
role: 'roles',
field: 'id',
right: {
field: 'id',
role: 'users'
}
}
}
});
and
Ext.define('App.model.security.Role', {
extend: 'App.model.Base',
entityName: 'Role',
fields: [
{ name: 'id' },
{ name: 'name'},
{ name: 'enabled', type: 'bool'}
],
manyToMany: {
RoleUsers: {
type: 'User',
role: 'users',
field: 'id',
right: {
field: 'id',
role: 'roles'
}
}
}
});
the tagfield definition:
xtype: 'tagfield',
fieldLabel: 'Roles',
displayField: 'name',
valueField: 'id',
stacked: true,
multiSelect: true,
filterPickList: true,
queryMode: 'local',
publishes: 'value',
bind: {
store: '{roles}',
value: '{userRoles}'
}
and the ViewModel:
Ext.define('App.view.security.user.UsersModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.users',
stores: {
users: {
model: 'App.model.security.User',
pageSize: 15,
autoLoad: true,
session: true
},
roles: {
model: 'App.model.security.Role',
autoLoad: true,
session: true
}
},
formulas: {
userRoles: {
bind: {
bindTo: '{mainGrid.selection.roles.data.items}',
deep: true
},
get: function(value){
return value;
},
set: function(value){
}
}
}
});
This is my very first project with Ext so maybe I'm missing some configuration at the model associations, I don't know.
I've googled a lot but lack information about the linked tagfield.
Any help will be gratefully appreciated.
Well I ended up using the formula by completing the missing code of the setter like this:
set: function(values){
//Delete the roles that were not established
var del = [], noadd = [];
var roles = this.get('mainGrid').selection.roles();
roles.each(function(record){
if (values.indexOf(record.get('id')) == -1) {
del.push(record);
}
else {
noadd.push(record.get('id'));
}
});
del.forEach(function(record){
roles.remove(record);
});
//Add the roles that didn't exist
var store = this.getStore('roles');
var allRecords = store.getData().getSource() || store.getData();
allRecords.each(function(record){
if (values.indexOf(record.get('id')) != -1 && noadd.indexOf(record.get('id')) == -1) {
roles.add(record);
}
});
}
Those arrays that I'm using are there because:
(del) cannot loop and delete over the same collection that I'm looping
(noadd) if I try to add an existing record into the roles collection it won't be added twice but at save time the existing record strangely appears as a create, I think this is a BUG.
I'll leave this question open for some time so if you know a better way to solve this you can make your contribution.
Thanks!