i've got referenced Users collection object in my MongoDB Items collection. Random Item document looks like this:
ps: to clarify, i really dont want to embed Items into Users collection.
Array
(
[_id] => MongoId Object
(
[$id] => 4d3c589378be56a008000000
)
[modified] => 1295800467
[order] => 1
[title] => MyFirstItem
[user] => Array
(
[$ref] => users
[$id] => MongoId Object
(
[$id] => 4d3c55e7a130717c09000012
)
)
)
So i need to find only items, which are assigned to the specific user. Find this question of my problem, but the solution didnt work for me.
MongoDB-PHP: JOIN-like query
Here is snippet of my code, givin' me no results at all.
$user = $db->users->findOne(array("_id" => new MongoID("4d3c55e7a130717c09000012")));
$items = $db->items->find(array("user" => array('$id' => $user["_id"])));
What is the correct way to finding that data? Should i instead put an user_id as a MongoID without reference?
Spent all my day with this, thanks in advance!
Try
$items = $db->items->find(array("user.$id" => $user["_id"]));
Related
I'm having trouble with putting this question to words so ill just use a simple example, hope the title sortof got my problem across.
I'm creating a blog site where I can create blogposts and people can post comments. This is all saved in JSON except for login details which are saved in MySQL.
Now saving the blogposts go fine but I'm now trying to save comments.
Lets say the blogpost array looks like this:
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
)
)
Now someone writes a comment on 'second blogpost', I save it into an array like this(user taken from MySQL):
Array
(
[user] => myusername
[comment] => first post was better!
)
Now I want to merge them like this:
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
[comments] => Array
(
[user] => myusername
[comment] => first post was better!
)
)
)
I tried searching for a while and I'd expect this to be somewhere on the site already but I can't find it. I tried a couple variations of array_push and array_merge but it always ended up replacing the relevant blogpost instead of adding onto it.
EDIT: Someone noted the new array can't just float around, I think it's better now.
If you had any related key between posts and comments ( like having post_id in comment array ) that would make more sense to merge/put them.
I assume that's your blogpost
Array
(
[0] => Array
(
[id] => 0
[title] => first blogpost
[content] => blogpost text
)
[1] => Array
(
[id] => 1
[title] => second blogpost
[content] => blogpost 2 text
)
)
And your comments should be like:
Array
(
[user] => myusername
[comment] => first post was better!
[post_id] => 1
)
That way, you would be able to find the matched blogpost.
But, outside of your data structure, here is an example to merge an item into an element of an array of array.
A nested loop example.
foreach($posts as &$post){
foreach($comments as $comment){
if($post['id'] == $comment['post_id']){
$post['comments'][] = $comment;
}
}
}
the key here is sending each reference of the element into loop by &$post and then just manipulate them in loop.
Working with indexed arrays. (Like you already have index names as post_id and a comments index as an empty array)
foreach($comments as $comment){
$posts[$comment['post_id']]['comments'][] = $comment;
}
When the blogpost is updated, I assume you can get the id of that blogpost.
Then you can check if your data structure already has a key "comments". If it does not, add the key and create an array containing the comment and the user as the first array.
If it already exists, add a new array with the user and the comment so that there can be multiple comments for each blogpost.
For example using array_map:
$blogPosts = array_map(function ($blogPost) use ($blogPostId, $comment) {
if ($blogPost["id"] === $blogPostId) {
isset($blogPost["comments"]) ? $blogPost["comments"][] = $comment : $blogPost["comments"] = [$comment];
return $blogPost;
}
return $blogPost;
}, $blogPosts);
Php demo
So I fixed it after a bit of thinking
This is the final structure:
Array
(
[0] => Array
(
[id] => 0
[title] => 1st post
[content] => 1st post works!
[date] => 21-01-2019
[comments] => Array
(
[0] => Array
(
[user] => Me
[comment] => hey 1
[date] => 12:02 21-01-2019
)
[1] => Array
(
[user] => Me
[comment] => hey 2
[date] => 12:03 21-01-2019
)
)
)
)
I added a timestamp because of a suggestion here. It's also a simplified version of what I actually use, I tried adding many more comments and on multiple posts which both work.
This is the code, I should mention the ID is in the URL and it's saved as JSON:
$filename = file.json;
$currentArray = json_decode(file_get_contents($filename), true);
$comment = $_POST['comment'];
$username = $_SESSION['username'];
$date = date("H:i d-m-Y");
$id = $_GET['id'];
Pretty straightforward so far, here is how the array is created:
$currentArray[$id]["comments"][] = array (
'user' => $username,
'comment' => $comment,
'date' => $date
);
[$id] saves it to the correct post, ["comments"] saves it to the comments key(or creates it) and the last [] gives every comment a different index inside the ["comments"].
$newJSON = json_encode($currentArray, JSON_PRETTY_PRINT);
file_put_contents($filename, $newJSON);
And lastly encoding it and saving it to JSON.
Hope this helps someone.
i have a collection "website" which data structure is like
[_id] => MongoId Object (
[$id] => 57beda7f0640fd14ca5cc307
)
[website] => MongoId Object (
[$id] => 57beda3d279871c80e8b4567
)
[url] => https://acb.com
[meta_tags] => Array (
[description] =>
[title] => Login
[title_length] => 18
)
ans same i have 10 rows of data.
now i am using laravel eloquent and i need to fetch all data which website is 57beda3d279871c80e8b4567 and title is empty or null.
who should i update my query for title attribute
$this->website->where('website', $website)->get();
Thanks.
Add another where condition:
$this->website
->where('website', $website)
->where('meta_tags.title', '=','')
->whereNull('meta_tags.title')
->get();
Laravel documentation: https://laravel.com/docs/5.2/queries
My data like this:
Array
(
[_id] => MongoId Object
(
[$id] => 51a6fca3f348aca011000000
)
[first_name] => Phan
[last_name] => Chuong
[interests] => Array
(
[0] => football
[1] => swimming
[2] => PHP
[3] => music
)
)
I want edit value PHP to PHP1 or set PHP to null. Please help me how can i do it? Thanks all!
You could use the MongoCollection::update() method like this:
// $c is your MongoCollection Object
$updatedata = array('$set' => array("interests.2" => "PHP1"));
$id = new MongoID('51a6fca3f348aca011000000')
$c->update(array("_id" => $id), $updatedata);
The update method needs two arrays, the first one will tell the DB which Object to update ( In this example where id = our id, always use the MongoID Object, always!), the second array defines what to update, note that you can get to values in nested arrays wit the dot like above. $set is an Field Update Operator, read more on them here:
http://docs.mongodb.org/manual/reference/operator/update-field/
Or you could just get the entire Array, change it, and save it back.
$cursor = $c findOne("_id",4cb30f560107ae9813000000);
$cursor['interests'][2] = 'whatever';
$c->update($cursor);
i think i have a problem with my schema design for my music app.
i have 3 collections: Artists, Tracks and Albums.
and 3 classes: artists, albums and tracks
document from artists:
[_id] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
[freeze] => false,
[genres] => Array,
[hits] => 0,
[name] => Sarya Al Sawas,
[pictures] => Array,
document from albums:
[_id] => MongoId Object
(
[$id] => 4ee88308615c218128000000
)
[name] => Sabia
[slug] => wafiq-habib-ft-sarya-al-sawas-sabia
[year] => 1999
[genres] => Array,
[pictures] => Array,
[artists] => Array
(
[0] => MongoId Object
(
[$id] => 4ee34a3b615c21b624010000
)
[1] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
)
document from tracks
[_id] => MongoId Object
(
[$id] => 4ee8a056615c21542a000000
)
[name] => Bid Ashok
[slug] => wafiq-habib-ft-sarya-al-sawas-bid-ashok
[genres] => Array,
[file] => /m/tracks/t.4ee8a05540c624.04707814.mp3,
[freeze] => false,
[hits] => 0,
[duration] => 303,
[albums] => Array
(
[0] => MongoId Object
(
[$id] => 4ee5cbc3615c216509000000
)
)
[artists] => Array
(
[0] => MongoId Object
(
[$id] => 4ee5bbfd615c219a07000000
)
[1] => MongoId Object
(
[$id] => 4ee34a3b615c21b624010000
)
)
first of all is that good schema design ??!
i designed this schema this way because of many to many relationships
sometimes tracks have 2 artists, and albums have 2 artists.
anyway i have problem querying the albums that attached to specific track.
lets say i'm on the artist page
i need to get all the artist albums and tracks so i do this:
$cursors = array(
'albums' => $this->albums->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
'tracks' => $this->tracks->find(array('artists' => $artist->_id))->sort(array('_id' => -1)),
'clips' => $this->clips->find(array('artists' => $artist->_id))->sort(array('_id' => -1))
);
foreach($cursors as $key => $cursor) {
foreach($cursor as $obj) {
$obj['name'] = ($this->lang->get() != 'ar' ? $obj['translated']['name'] : $obj['name']);
$obj['by'] = $this->artists()->get($obj['artists'])->toString('ft');
${$key}[] = $obj;
}
}
i need to loop on all tracks and get their album names lets say this artist has 3000 tracks
i think it will be very slow....
so my question is: Is That a good Schema Design ?
Well, this is a very relational problem, and using a non-relational database for such a problem requires some effort. In general, I think your schema design is good.
What you're describing is called "the N+1 problem", because you'll have to make N+1 queries for N objects (in your case, it's more complicated, but I guess you get the idea).
Some remedies:
You can use the $in operator to find e.g. all tracks of a certain artist:
db.tracks.find({"artists" : { $in : [artist_id_1, artist_id_2, ...] } });
This doesn't work if the array of artists grows huge, but a few hundred, maybe a thousand should work fine. Make sure artists is indexed.
You can denormalize some of the information that is needed very often. For example, you might want to show the track list very often, so it makes sense to copy the artist's names to every track. Denormalization depends mostly on what you're trying to achieve from an end-user perspective. You might not want to store each and every artist's name in full, but only the first 50 characters because the UI doesn't show more in the overview anyway.
In fact, you're already denormalizing some data, such as the artist ids in album (which are redundant, because you could get them via the tracks as well). This makes queries easier, but it will be more write-heavy. Updates are ugly because you'll have to make sure they propagate through the system.
In some cases, it might make sense to 'join' on the client(!) rather than the server. This doesn't really fit your problem well, but it's noteworthy: suppose you have a list of friends. Now the sever will have to look up each friend's name whenever it displays them. Instead, it could provide you with a lookup table ids/friends, and the server only serves the ids. Some JavaScript could replace the ids with the real names from the client's cache.
This is driving me crazy, I am trying to get to a specific part of this object and it is driving me crazy, here is the object contents:
XMLHandler Object
(
[doc:XMLHandler:private] => SimpleXMLElement Object
(
[#attributes] => Array
(
[state] => Live
)
[newsListItem] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[href] => http://api.contentplus.co.uk/6cb5ea15-d6b1-4c40-9db7-cb2a3315080b/news/800773226/
)
[id] => 800773226
[publishDate] => 2011-10-24T10:04:49
[lastModifiedDate] => 2011-10-24T11:20:40
[headline] => Relationships matter on social media
)
)
)
[format] => html
)
I want to get the value of [id] I am trying to access it like this:
echo $niList->doc->newsListItem[0]->id;
but this is giving me nothing, I know I am close (well I hope I am) but I just cant quite get it right, could anyone help please.
Thanks all.
Your object dump says
doc:XMLHandler:private
which means doc is a private property of XMLHandler. As such, you can only access it from within that object via $this. But you are trying to access it from outside the object when you do
echo $niList->newsListItem[0]->id;
This wont work. Add a method to that XMLHandler object that does what you want to do with that newslistitem id. Also see the chapter on Visibility in the PHP Manual:
http://docs.php.net/manual/en/language.oop5.visibility.php