I have two collections, Group and User. Originally, my Group document contained an array of User references. But I've changed my mapping so that Users now hold a reference to a Group. I am wondering how I can write a query to update all the existing User documents to reference the group that is currently referencing them, then remove any references on the groups.
I didn't notice the language you are using at first - I had to do something very similar in Python so here is my example code:
# I changed my collection names to users/groups hope I mapped them right :)
users = db.users
groups = db.groups
for u in users.find():
grp = groups.find( { "users" : u['userId'] } )
u['groups'] = [ g['groupId'] for g in grp ]
users.save(u)
Basically, for every user, I look in groups to find a list of groups which contain userId in the array users, and I make a list called groups in u and when I save it adds an array of groups to users document.
Should be not hard to do it in PHP
$users = $db->users;
$groups = $db->groups;
// find all users
$ucursor = $users->find();
// iterate through users, find groups which have the user,
// update user with array of groups
foreach ($ucursor as $u) {
$gcursor = $groups->find( ... );
foreach ($gcursor as $g) {
...
}
}
But this seems like a one time operation, you could do it in mongo shell using something similar to:
var users = db.users.find();
while (users.hasNext()) {
u = users.next();
var gs = db.groups.find({"users":u.userId},{"groupId:1}).toArray();
db.users.update({"groupId":groupId},{$set:{"groups":gs}});
}
Related
I have different communities in my database, such as: community_newsfeed, community_marketplace, community_games_requested, community_games_offered, events and custom_posts.
Each of those communities stores a post_id, as well as the user_id.
Then I have a community_users table that stores user_id and community_id.
I want to create a mechanism which I, as the authenticated user, can view all the posts of a user, as long as that user and I belong to the same community.
And on that regard, I must view only the posts for the communities which we both belong to.
So I do the following:
Get all the community id's of the communities which I(auth user) belong to:
$community_user_member = DB::table('community_users')->whereUserId($user->id)->pluck('community_id')->toArray();
Then I do the same for the user which I want to see the posts:
$requested_user = DB::table('community_users')->whereUserId($user_id)->pluck('community_id')->toArray();
Fine. Now I use array interect to give me all the community_id that we share only:
$members = array_intersect($community_user_member, $requested_user);
Now, this is where I get stuck.
How can I get the communities which the id match the values I get in the $members value(not the key) and the user id matches $user_id( this is passed in the url )?
if(!empty($members)){
$newsfeed = CommunityNewsfeed::whereIn('newsfeed_community_id', $members)->whereUserId($user_id)->get();
}
I am sure that this user has 4 posts from community_newsfeed table, but I only see two posts, and also I dont see the correct posts.
Live example:
User A belongs to community_newsfeed.
User B belongs to community_newsfeed and community_marketplace.
User A must see the community_newsfeed data where user_id is the id of User B.
Updated
Another option I tried was to use the in array function:
$common = [];
foreach ($community_user_member as $key => $member) {
if (in_array($member, $requested_user)) {
$common[] = $member;
}
}
print_r($common);
The end result should be something like this:
$common = [ '4','5','10','20' ];
Because then I would be able to loop through $common array and do whatever I want.
But I get the following error when I refresh the page:
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
In Joomla 2.5.14, I have a script that gets the current user group id, like:
$groups = $user->get('groups');
foreach($groups as $group) {
echo "<p>Your group ID is:" . $group . "</p>";
};
Now, I need to count the number of articles this user is able to read, given his access level.
For that, I need to select the access level from the viewlevels table, that looks like this:
id title rules JSON encoded access control.
1 Public [1]
2 AccessA [13,8,16,17]
3 AccesssF [8]
4 AccessD [14,8]
6 AccessB [8,16,17]
7 AccessC [8,17]
So, for example, Group 17 may read the articles in AccessA, AccessB and Access C.
I tried the following query, but it isn't selecting any rows:
$query="SELECT * FROM xmb9d_viewlevels WHERE rules LIKE '%.$group.%'";
How can I select all the acess levels for the current user group and then count the number of articles he's able to read?
Thanks for helping!
First
https://github.com/joomla/joomla-cms/blob/master/libraries/joomla/access/access.php#L285
JAccess::getGroupsByUser($userId, $recursive = true)
Will get you the groups a user is matched to including via inheritance (unless you make $recursive false)
https://github.com/joomla/joomla-cms/blob/master/libraries/joomla/access/access.php#L402
JAccess::getAuthorisedViewLevels($userId) will give you all the view levels a user is allowed to see as an array.
If you do
$allowedViewLevels = JAccess::getAuthorisedViewLevels($userId);
if nothing else you could do
$implodedViewLevels = implode(',', $allowedViewLevels);
....
$query->select($db->quoteName('id'))
->from('#__content')
->where($db->quoteName('access') . 'IN (' . $implodedViewLevels . ')';
....
(not tested but you get the general idea).
In joomla always try to let the api do the work for you rather than fight with it.
I think you just need to remove the periods from within the LIKE clause. Such as:
$query="SELECT * FROM xmb9d_viewlevels WHERE rules LIKE '%$group%'";
Also, to make it not specific to the database you should substitute #__ (Note: it's two underscores) for the table prefix:
$query="SELECT * FROM #__viewlevels WHERE rules LIKE '%$group%'";
I am trying to set up some data and am fairly new to cypher queries. I m doing a project whereby nodes and relationships are created as part of a soccer team.
for example I am creating nodes on games and referees only at the moment. My logic is that I read in data for a game and if the referee does not exist as a node, to create him/her. If on a future game i see a referee that already exists that I just relate them to the game rather then creating a duplicate record. I am doing the following and wanted to see if my logic made sense before I even attempted to populate my data.
//JUST CREATED A GAME NODE called $GameNode
//let's search if the referee exists
$queryString = "START n=node({nodeId}) ".
"MATCH (n)<-[:REFEREED]-(x)".
"WHERE x.name = {name}".
"RETURN x";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryString, array('nodeId' => 0, 'name' => $referee['referee_name']));
$result = $query->getResultSet();
$referee = 0;
if (count($result)==0)
{
//create referee as he/she does not exist
$referee= $client->makeNode();
$referee->setProperty('name', $referee['referee_name'])
->save();
}
else
{
//let's point the referee to this law case also
$referee = $client->getNode($result['x']->getProperty('id'));
}
$referee->relateTo($GameNode, 'REFEREED')
->save();
many thanks in advance
This should work but does a lot of roundtrips.
You can use Cypher only for this task:
Neo4j 1.9 use CREATE UNIQUE
START root=node({nodeId})
CREATE UNIQUE (root)<-[:REFEREED]-(referee {name: {name}})
RETURN referee
In Neo4j 2.0 you can use MERGE
MERGE (referee:Referee {name: {name}})
RETURN referee
Please also use better names for your identifiers.
I have a set of Organizations and their Board Members.
All organizations have board members and many board members are on the board of more than one organization.
I am using JIT Hypertree to illustrate their relationships. The JIT Hypertree schema requires that one item be the parent of all and is drawn based on a single JSON array.
I would love to have the re-centering event query and re-populate the graph based on the change. Then 2 levels would be fine but I have not been able to work out how to do that.
The code I have at present recurses manually for three levels from the starting organization but what I want is to re-curse through all related records.
So it would start with an Org and add Org's array of children (board members). Then fetch all of the boards (other than current Org) for each board member and add those as children of the board member.
This would continue until each trail dead ends - presumably at a board member who only belongs to one board.
Anyone have advice on how to create this array and avoid duplicates?
$board = $center->board();
$top['id'] = $center->ID;
$top['name'] = $center->Org;
$top['children'] = array();
if ($board) {
foreach ($board as $b) {
$child['id'] = $b->ID;
$child['name'] = (strlen(trim($b->Last)) > 0) ? $b->First . ' ' . $b->Last : 'Unknown';
$child['data']['orgname'] = $center->Org;
$child['data']['relation'] = $b->Role;
$child['data']['occupation'] = $b->Occupation;
$child['children'] = array();
$childboards = $b->boards();
if ($childboards) { foreach ($childboards as $cb) {
$gchild['id'] = $cb->ID;
$gchild['name'] = $cb->Org;
$gchild['data']['orgname'] = (strlen(trim($b->Last)) > 0) ? $b->First . ' ' . $b->Last : 'Unknown';
$gchild['children'] = array();
$childboardmembers = $cb->board();
if ($childboardmembers) { foreach ($childboardmembers as $cbm) {
$ggchild['id'] = $cbm->ID;
$ggchild['name'] = (strlen(trim($cbm->Last)) > 0) ? $cbm->First . ' ' . $cbm->Last : 'Unknown';
$ggchild['data']['orgname'] = $cb->Org;
$ggchild['data']['relation'] = $cbm->Role;
$ggchild['data']['occupation'] = $cbm->Occupation;
$ggchild['children'] = array();
$gchild['children'][]= $ggchild;
}}
$child['children'][]= $gchild;
}}
$top['children'][] = $child;
}
}
$top['data'] = array();
$top['data']['description'] = $center->Desc;
echo json_encode($top);
// Edit 2011.10.24 In Re hakre response
My data structure is a table of Organizations with unique IDs, a table of People with Unique IDs, and then a bridging table for the two specifying Organization (Entity) and Person and the Role the Person is playing in the Entity. A typical many-to-many. No sub-boards at all. I made an image of it which now seems kind of pointless but I'll add it at the bottom.
The JIT library data structure is a little nuts (to me) in that it goes like this in their band example:
Top: Nine Inch Nails
Child: Jerome Dillon
Child: Howlin Maggie (another band)
{all the bands' members and then all of their bands...}
So the organization (band) is treated as though it is a Person even though it is comprised of a number of Persons. And when I recurse using the code above I get (I think) terrible bloat but the JSON it makes works correctly despite bloat.
Example JSON and Example Visualization
// End Edit
Your question is hard to answer in the sense that your data-structure is mainly unknown.
For the graphical represenation you only need to provide simple relationships if I understand that correctly:
*- Parent
+- Child
+- Child
...
`- Child
Your data structure has a different format, I don't know specifically but it's something like:
Org <-- 1:n --> Board
Board <-- n:n --> Board # If you have sub-boards
Board <-- n:n --> Member
Whichever your data is represented, to map or transpose your data onto the required structure for the graphical representation, you need some functions that take care of that.
To do that you need to share classification/type between both and specific keys, so that you can look-up the needed data from the event to return the data. For example:
if (request_parent_is_org())
{
$id = request_parent_id();
$parent = data_get_board($id);
$parent->addChildrent(data_get_board_children($id));
}
else
{
... # All the other decisions you need to take based on request type
}
view_response_to_json($parent);
What you have with your many-to-many data model is a graph. JIT is designed for trees.
To put it another way, JIT will not correctly show the crossing lines that are represented in the data whenever a single person is connected to multiple organizations.
I'd recommend a proper network graph visualization - D3.js has a great implementation for modern browsers.
The JSON data format it uses is actually easier to implement given your table structure - for all the organizations and people, you define objects:
{
"name": "Mme.Hucheloup",
"group": 1
},
{
"name": "Afton School Board",
"group": 2
}
And for each association in your association table you define connection objects that wire them together:
{
"source": 1,
"target": 2
},
The fancy coding in D3 takes care of the rest. Good luck!
You can use function below:
function get_orgs_and_childs ($child_id, $found = array())
{
array_push ($found, $child['name']);
if($child['children'])){
$found[] = get_parents($child['id'], $found);
}
return $found;
}
Call it using:
$orgs = get_orgs_and_childs($child['id']);
I have an object oriented PHP application. I have a simple hierarchy stored in an SQL table (Chapters and Authors that can be assigned to a chapter).
I wrote the following method to fetch the chapters and the authors in a single query and then loop through the result, figuring out which rows belong to the same chapter and creating both Chapter objects and arrays of Author objects.
However, I feel like this can be made a lot neater. Can someone help?
function getChaptersWithAuthors($monographId, $rangeInfo = null) {
$result =& $this->retrieveRange(
'SELECT mc.chapter_id, mc.monograph_id, mc.chapter_seq, ma.author_id, ma.monograph_id, mca.primary_contact, mca.seq, ma.first_name, ma.middle_name, ma.last_name, ma.affiliation, ma.country, ma.email, ma.url
FROM monograph_chapters mc
LEFT JOIN monograph_chapter_authors mca ON mc.chapter_id = mca.chapter_id
LEFT JOIN monograph_authors ma ON ma.author_id = mca.author_id
WHERE mc.monograph_id = ?
ORDER BY mc.chapter_seq, mca.seq',
$monographId, $rangeInfo
);
$chapterAuthorDao =& DAORegistry::getDAO('ChapterAuthorDAO');
$chapters = array();
$authors = array();
while (!$result->EOF) {
$row = $result->GetRowAssoc(false);
// initialize $currentChapterId for the first row
if ( !isset($currentChapterId) ) $currentChapterId = $row['chapter_id'];
if ( $row['chapter_id'] != $currentChapterId) {
// we're on a new row. create a chapter from the previous one
$chapter =& $this->_returnFromRow($prevRow);
// set the authors with all the authors found so far
$chapter->setAuthors($authors);
// clear the authors array
unset($authors);
$authors = array();
// add the chapters to the returner
$chapters[$currentChapterId] =& $chapter;
// set the current id for this row
$currentChapterId = $row['chapter_id'];
}
// add every author to the authors array
if ( $row['author_id'] )
$authors[$row['author_id']] =& $chapterAuthorDao->_returnFromRow($row);
// keep a copy of the previous row for creating the chapter once we're on a new chapter row
$prevRow = $row;
$result->MoveNext();
if ( $result->EOF ) {
// The result set is at the end
$chapter =& $this->_returnFromRow($row);
// set the authors with all the authors found so far
$chapter->setAuthors($authors);
unset($authors);
// add the chapters to the returner
$chapters[$currentChapterId] =& $chapter;
}
}
$result->Close();
unset($result);
return $chapters;
}
PS: the _returnFromRow methods simply construct an Chapter or Author object given the SQL row. If needed, I can post those methods here.
EDIT: i cannot append items one author at a time to chapter. I need to add them all at once because of the way the Chapter object is structured.
I guess the goal is to make this simpler and easier to understand. How about something like this pseudocode? :
execute query
chapters = array()
for each result:
chapter = result['chapter']
author = result['author']
if (!isset(chapters[chapter]))
chapters[chapter] = new Chapter
chapters[chapter].authors.append(author)
Rather than creating an authors array, populating it, storing it, then starting over for each chapter, we can make the code more readable and shorter (albeit a little slower, probably). In short, for each result, it looks to see if the chapter is in the chapters array. If not, it creates it. Then it adds the author to the chapter.