how to query two collections in once with mongodb - php

I have two collections like this:
var Users = [
{
'ID' : 1,
'NAME' : 'Seth'
},
{
'ID' : 2,
'NAME' : 'John'
}
];
var Posts = [
{
'ID' : 1,
'TEXT' : 'blalalalalala...',
'USER' : 1
},
{
'ID' : 3,
'TEXT' : 'blalalalalala....',
'USER' : 2
}
];
How can I get the posts created by Seth without his ID? (Query By NAME : Seth)

If this is your schema, then there is no way of getting the posts for a given user by name in one query. In your application, you would have to perform two queries. The first to get the ID given a NAME and the second to get the posts given that USER. This is referred to in the MongoDB documentation as "manual referencing" and it would work something like this:
var id = db.Users.findOne({ "NAME" : "Seth" });
var posts = db.Posts.find({ "USER" : id });
If you indeed want to do this with one query, then you will have to look into embedding posts in an array inside the user documents, using DBRefs (which you need to be careful with), or in the case of some ODMs like Mongoose, using "population".
UPDATE:
Given the new information presented by the OP, in the case where you want to find all posts for users that have not been deleted, and if you don't want to iterate through a large array every time, I would suggest adding a USER_DELETED field that can be set to true when a user is deleted.
So in the event that a user with { "ID" : id } is deleted, you would run a query as follows:
db.Posts.update({ "USER" : id }, { "$set" : { "USER_DELETED" : true } });
That would then mark all of the posts for that user as belonging to a user that has been deleted. So when you want to retrieve the posts for all users that are still around, you would run:
db.Posts.find({ "USER_DELETED" : { "$ne" : true } });
Or you could do something along those lines. If you know that all the documents have a USER_DELETED field set to false if the user is still around, then you can just query for those that have the flag set to false.
Of course you will still have to transform the old data to follow this pattern, but that can be achieved with a one time operation that consists of:
Finding all of the users that have been deleted.
Finding the posts for each of those users.
Adding the USER_DELETED flag for each of those posts.
That should be a better way of approaching the problem you are facing.

Related

PHP / Laravel Firebase Realtime Database updating a specific field

I'm trying to update firebase realtime database using kreait/firebase-php package.
Here's my tree:
I need to update the child of /detail/pesan/1/<unique ID> which have is_read value of false and update it to true.
Here's part of my code:
$database = $firebase->getDatabase();
$id_pesan=1;
/*
Update Firebase is_read
*/
$update = ['/is_read' => "true"];
$updatePesan_1 = $database
->getReference('chat/detail/'. $id_pesan)
->orderByChild('is_read')
->equalTo('false')
->update($update);
But i get this error :
Call to undefined method Kreait\Firebase\Database\Query::update()
when I change it to get the value first then update / set it :
$updatePesan_1 = $database
->getReference('chat/detail/'. $id_pesan)
->orderByChild('is_read')
->equalTo('false')
->getValue()
->set($update);
I get this error :
{"status":"error","error":400,"message":"Index not defined, add \".indexOn\": \"is_read\", for path \"/chat/detail/1\", to the rules"}
What I'm trying to do is filter / query database first to find child of specific tree which have is_read = false and update the value from "false" to "true".
Is it possible to do query of firebase database then updating it?
If yes how do I fix my code to achieve that?
Here's my solution
Okay so after many research and trial and error.
I did a couple of things :
Change the new rule to enable editing specific field on firebase database
Change the PHP code since I am unable to do filter / query then update. so I had to do it without filter / query and then updating data
1. Changes to Firebase database Rule
I change the rule to this :
{
"rules": {
".read": true,
".write": true,
"chat": {
"detail": {
"$id_pesan" :{
".indexOn": ["is_read"]
}
}
}
}
}
Some short explaination :
The data is stored in chat/detail///
since I need to be able to change what's inside I added ".indexOn" : ["is_read"] I change the rule and put indexing inside chat/detail/.
2. Change PHP code
At first what I want to do is this :
Initialize Firebase
Set references
Do Update call while query-ing field (in 1 call)
But it seems the package doesn't support what I wanted to do. so instead what I had to do is I have to query the field and get the unique ID value first. Then I made it into an Associative Array, then use it to update Database
here's the new code
//initialize
$database = $firebase->getDatabase();
//get value of all the unique ID
$getValue = $database
->getReference('chat/detail/'. $id_pesan)
->orderByChild('is_read')
->equalTo('false')
->getValue();
//initialize Array
$update = [];
//make the array necessary to update the firebase database
/*
What the Array should looks like
<Unique ID>/<variable I wanted to change> => "<new Value>"
Example :
"-IUAYS678/is_read" => "true"
"-JVHBY817/is_read" => "true"
*/
foreach($updatePesan_1 as $k => $v)
{
$update[$k. "/is_read"]="true";
}
//Update the Firebase Database
$updatePesan_1_process=$database->getReference('chat/detail/'. $id_pesan)
->update($update);
I hope this helps

CakePhp 3: switch between insert/update associated fields in a key-value table

I'm having trouble modifying the logic for saving one of my associated table.
The two tables are:
Clients
ClientMetadatas (storing the client's metadata with key/value pairs)
In the Clients Controller, the method edit(), classic, baked with cakephp, with the associated table in addition:
$client = $this->Clients->get($id, [
'contain' => ['ClientMetadatas']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$client = $this->Clients->patchEntity($client, $this->request->data);
if ($this->Clients->save($client, ['associated' => ['ClientMetadatas']])) {
$this->Flash->success(__('The client has been saved.'));
} else {
$this->Flash->error(__('The client could not be saved. Please, try again.'));
$this->response->statusCode(500);
$client=$client->errors();
}
}
$this->set(compact('client'));
$this->set('_serialize', ['client']);
An example of how I edit a client and its metadatas would be, calling '/clients/edit/clientid.json'
{
"firstname": "John",
"firstname": "Smith",
"client_metadatas":
[
{
"name": "test",
"value": "test"
}
]
}
Here's my problem: I'd like to verify if there is no metadata existing with this client_id and metadata's name. If it exists, I'd perform an update rather than an insert.
It seems that the ideal solution would be to do it in the Model directly.
I tried to use the callback methods:
beforeSave(), but I wasn't able to modify the entity
beforeFind(), but I wasn't able to modify the query
Any advice on how to properly do the verification and the switch between insert/update before saving the entity?
PS: I hope no information in missing. If it the case, don't hesitate, I'll add them...
Thank you !
Insert/update determination works out of the box
CakePHPs ORM can do that on its own out of the box. Whether an update or an insert is being performed, is figured based on the persistence status of the entity that is to be saved, ie based on the return value of Entity::isNew().
Quote from the Table::save() API docs:
This method will determine whether the passed entity needs to be inserted or updated in the database. It does that by checking the isNew method on the entity.
Primary key values need to be present
In order to have this being set up properly automatically, you have to provide the possible existing primary key values of those records in your data, so that the marshaller can prepare the entities properly when patching in the request data.
So where/however you are preparing that data, make sure that you include the primary key value(s) in case they exist, so that you send something like this:
{
"firstname": "John",
"firstname": "Smith",
"client_metadatas":
[
{
"id": 1,
"name": "existing",
"value": "existing"
},
{
"name": "non-existing",
"value": "non-existing"
}
]
}
The first set would be an update (given that a record with such an id primary key value exists), the second one would be an insert.
Find existing records based on custom criteria
Surely it's also possible to handle things on your own, ie without passing the primary key values in the request data, at least as long as there is another unique column. Searching for other, custom criterias, like the name of the record, and then modifying the entity accordingly so that the respective row is being updated, should work fine.
You could do that in the beforeSave callback/event, or even in the beforeMarshall callback/event, depending on when you want to this to apply, something along the lines of:
public function beforeSave(
\Cake\Event\Event $event,
\Cake\Datasource\EntityInterface $entity,
\ArrayObject $options
)
{
if ($entity->isNew()) {
$existing = $this
->find()
->where([
'name' => $entity->get('name')
])
->first();
if ($existing) {
$entity->set('id', $existing->get('id'));
$entity->isNew(false);
}
}
return true;
}
See also
Cookbook > Database Access & ORM > Saving Data > Updating Data
Cookbook > Database Access & ORM > Saving Data > Merging Request Data Into Entities > Patching HasMany and BelongsToMany
API > \Cake\Datasource\EntityInterface::isNew()
API > \Cake\ORM\Table::save()

CakePHP how to add data from another field of a related model

This is one of my first applications out of tutorials so I don't know how to express my issue well.
Well I have these 2 tables:
User ( id, code )
Hours ( id, user_id, created)
I want to know how I can add an entry to the Hours table using the user_code.
I tried to grab the data of the User table with the code value and then findBy and pass for the patchEntity but it did not work.
I don't have a whole lot of information to work with, but I'll give it a go.
I want to know how I can add an entry to the Hours table using the
user_code
You mention using patchEntity, so that's updating information that's already there. Assuming user_code is the 'code' column you're talking about there, first find the user by his code:
$users_tbl = TableRegistry::get('Users');
// find the user
$user = $users_tbl->findByCode($user_code)->first();
if ($user) {
// replace '$this->request->data() with whatever patch data you wanted
$users_tbl->patchEntity($user, $this->request->data(), [
'associated' => ['Hours']
]
if ($users_tbl->save($user)) {
// success!
} else {
// error!
}
} else {
// error!
}
It will also depend on how you have the data you passed in (where my '$this->request->data() is, or whatever your array might be) - it needs to match the right column names and be in the correct format listed here.
However, this is updating the data. Just adding the data, you can load the hours table and add a new entry with the user_id acquired from the user search:
$hours_tbl = TableRegistry::get('Hours');
$hours = $hours_tbl->newEntity([
'user_id' => $user->id // $user populated from same method earlier
]);
/* assumed 'id' was autoincrementing and 'created' was populated
through Timestamp behavior */
if ($hours_tbl->save($hours)) {
// yay!
} else {
// boo
}

Getting Like and Comment

I'm using facebook PHP SDK , facebook api version 2.2.
I want to display the user news feed. I'm using the following api get this.
$facebookConncetion->api("$oauthUserId/home",
'GET',
array("access_token" => $accessToken,
"limit" => '15',
"comments.limit" => 10,
"likes.limit" => 10
)
);
But it returns all the post in the user home page with 10 comment and 10 likes and it does not return summary of like and comment. How can I format this api to get the like and comment summary per post?
You have to add .summary(true) and .filter(stream) to the like and comment request just like you added the limit.
Summary will return something like this:
"comments" : {
"data" : [ ARRAY OF COMMENTS ] },
"paging" : { PAGING CURSORS/URLS }.
"summary" : {
"total_count" : NUMBER OF COMMENTS
}
},
Adding .filter(stream) will return ALL comments/likes. With out this there may be some missing due to Facebook filtering them out due to their low "story" value. It will also order all comments/likes in true chronological order.
https://developers.facebook.com/docs/graph-api/reference/v2.2/object/comments
Look under "Modifiers" works with both comments and likes.

How do you show the value assigned to an integer from a lookup table with yii?

In my form, I created the value by populating the dropbox from values from a table.
<?php echo $form->dropDownList($model,'status', CHtml::listData(Statusprospect::model()->findAll(), 'id', 'status'),array('prompt' => 'Select')); ?>
When I view the record it has a 1, as it should for status. How do I make it display the value when the record is viewed, instead of the 1.
The view file code that currently displays the field is this:
<?php echo CHtml::encode($data->status); ?>
The Model does have the relationship defined:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'status0' => array(self::BELONGS_TO, 'Statusprospect', 'status'),
);
}
How would I accomplish showing the value instead of the number?
Right now this should work $data->status0->status.
Take care that $data->status0->status might not be set if $data->status can be null so make a check beforehand if that is the case. You can use
CHtml::encode(isset($data->status0->status) ? $data->status0->status : '-');

Categories