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
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".
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();
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)
);
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.
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!