I have this document in mongo:
array (
'_id' => new MongoId("509356edf275130917000000"),
0 =>
array (
'id1' => '1000',
),
1 =>
array (
'book' =>
array (
'id2' => '0',
'name' => 'Example',
),
),
)
and i want to add a book to "book" array:
$coll->update(array(array("id1"=>'1000'),
'$push'=>array('book'=>array(
"id2"=>"1",
"name" =>'War and peace'))));
but nothing happens, anyone know how to do this?
book is single array. You can't update.
Update records based on a given criteria
$collection->update($criteria, $newdata);
Example:
[
'_id' => new MongoId("509356edf275130917000000"),
'ids' => [1, 2, 3],
'books' => ['Book1', 'Book2']
]
$data = ['books' => 'Book3'];
$collection->update(
// Criteria
["_id" => new MongoId("509356edf275130917000000")],
// New Object
['$push' => $data]
);
Related
Kinda stuck.
We have products which we offer to companies.
so it would be an mm field which is no problem to implement, but the problem comes with date, since each product has expire date based on company.
so decided to remove product mm and put product id with date into company as one field.
but since input which we send is an array it's not possible to save it there.
How can i solve this problem ?
this is my tca for that field:
'product' => [
'exclude' => true,
'label' => 'LLL:EXT:wemessage_checklist/Resources/Private/Language/locallang_db.xlf:tx_wemessagechecklist_domain_model_company.product',
'config' => [
'type' => 'user',
'userFunc' => Wemessage\WemessageChecklist\UserFunc\Checklist::class.'->renderChecklists',
],
],
Here is function to render html:
public function renderChecklists($PA, $fObj){
$checked = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_wemessagechecklist_domain_model_company', 'hidden=0 and deleted=0 and uid='.$PA['row']['uid'].' and pid='.$PA['row']['pid']);
$allProducts = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tx_wemessagechecklist_domain_model_product', 'hidden= 0 and deleted = 0');
foreach($allProducts as $product){
$html .= '<div>';
$html .= '<input type="hidden" name="data[tx_wemessagechecklist_domain_model_company]['.$PA['row']['uid'].'][product]['.$product['uid'].']" class="product"/>';
$html .= '<input type="checkbox" class="tocheck" value="'.$product['uid'].'" /><span style="margin: 0 10px;">'.$product['name'].'</span><span style="margin: 0 10px;">Verval datum</span><input type="date" class="date" />';
$html .= '</div>';
}
$html .= '<script>
TYPO3.jQuery(".tocheck").click(function(){
var val = TYPO3.jQuery(this).val();
if(TYPO3.jQuery(this).prop("checked")){
TYPO3.jQuery(this).parent().find(".product").val(val);
}
});
TYPO3.jQuery(".date").change(function(){
var x = new Date(TYPO3.jQuery(this).val()).getTime();
var b = TYPO3.jQuery(this).parent().find(".product").val();
TYPO3.jQuery(this).parent().find(".product").val(b+":"+x);
});
</script>';
return $html;
}
probably another option is to implement AJAX calls to process data in standalone table. although if there is another solution will be glad to hear it.
You should still go for an MM relation or better inline (IRRE) connection from company to product, since these can have an own TCA too, thus making it possible to add starttime, endtime and other values to the MM relation record itself.
The concept is called "intermediate table" and is described here: https://docs.typo3.org/typo3cms/TCAReference/ColumnsConfig/Type/Inline.html#attributes-on-anti-symmetric-intermediate-table
Here is a modified TCA taken from the IRRE tutorial extension. It contains just the necessary settings for the connections and the timestamp field - feel free to add your own fields for companies and products:
$TCA["company"] = Array (
"columns" => Array (
"products" => Array (
"config" => Array (
"type" => "inline",
"foreign_table" => "company_product_intermediate",
"foreign_field" => "company_id",
"foreign_sortby" => "companysort",
"foreign_label" => "product_id",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
);
$TCA["company_product_intermediate"] = Array (
"columns" => Array (
"company_id" => Array (
"config" => Array (
"type" => "select",
"foreign_table" => "company",
"maxitems" => 1,
)
),
"product_id" => Array (
"config" => Array (
"type" => "select",
"foreign_table" => "product",
"maxitems" => 1,
)
),
"companysort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
"productsort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
"timestamp" => Array (
"config" => Array (
"type" => "input",
)
),
),
);
$TCA["product"] = Array (
"columns" => Array (
"companies" => Array (
"config" => Array (
"type" => "inline",
"foreign_table" => "company_product_intermediate",
"foreign_field" => "product_id",
"foreign_sortby" => "productsort",
"foreign_label" => "company_id",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
);
I have a MongoDB document that is structured similar to the structure below follows. I am searching based on people.search_columns.surname and people.columns.givenname. So for example, when I search for the given name of "Valentine", I want to get the document back, but Nicholas Barsaloux should not be included.
Data structure:
[_id] => MongoId Object (
[$id] => 53b1b1ab72f4f852140dbdc9
)
[name] => People From 1921
[people] => Array (
[0] => Array (
[name] => Barada, Valentine
[search_columns] => Array (
[surname] => Array (
[0] => Mardan,
[1] => Barada
)
[givenname] => Array (
[0] => Valentine
)
)
)
[1] => Array (
[name] => Barsaloux, Nicholas
[search_columns] => Array (
[surname] => Array (
[1] => Barsaloux
)
[givenname] => Array (
[0] => Nicholas
)
[place] => Array (
)
)
)
)
Here is the code I was working on:
$criteria = array("people" => array(
'$elemMatch' => array("givenname" => "Valentine")
));
$projection = array("people" => true);
$documents_with_results = $db->genealogical_data->find($criteria, $projection)->skip(0)->limit(5);
Currently that code returns zero results.
Since the arrays are nested you cannot use basic projection as you can with find. Also in order to "filter" the array contents from a document you need to "unwind" the array content first. For this you use the aggregation framework:
$results = $db->genealogical_data->aggregate(array(
array( '$match' => array(
'people.search_columns.givenname' => 'Valentine'
)),
array( '$unwind' => '$people' ),
array( '$match' => array(
'people.search_columns.givenname' => 'Valentine'
)),
array( '$group' => array(
'_id' => '$id',
'name' => array( '$first' => '$name' ),
'people' => array( '$push' => '$people' )
))
));
The point of the first $match stage is to reduce the documents that possibly match your criteria. The second time is done after the $unwind, where the actual "array" items in the document are "filtered" from the results.
The final $group puts the original array back to normal, minus the items that do not match the criteria.
I am trying to use the aggregation function to display info in a chart. For this example, a document in the collection looks like this (excluding unnecessary fields for this query):
{
'locid' : <someid>, #Reference to a city & state collection
'collat' : <dateobj>, #a date object when this entry was saved
'pid' : <someid>, #Reference to a person collection
'pos' : <int> #Value I am interested in matching with location & date
}
So I basically start with a pid. I use this as my first $match parameter to limit the amount of data that gets thrown into the pipeline.
array(
'$match' => array(
'pid' => new \MongoId($pid)
)
),
So now that I have selected the correct pid, I tell it I only want/need certain fields:
array(
'$project' => array(
'pos' => 1,
'collat' => 1,
'locid' => 1
)
),
The second match is to say I only care about these locations right now ($ids contains an array of locid):
array(
'$match' => array(
'locid' => array('$in' => $ids)
)
),
And finally, I am saying group all the returned documents by collat and locid
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
)
)
)
While the query completes OK and returns data, I am not getting the pos field back, it is only returning the locid and collat.
Questions
Isn't that what $project is for? I use it to tell the driver what fields I want returned?
Once I get the pos field returning as well, how can I tell the driver I only want the lowest value for each locid & collat combo pair? So say there are two entries for that date, location, and person: 4 & 8. I only care about pos=4
My end goal is to create a line chart with the X-Axis as the dates (from collat) and the Y-Axis will be the pos field, and each line will plot individual locid data.
Here is the entire parameters being sent to the aggregation driver.
$ops = array(
array(
'$match' => array(
'pid' => new \MongoId($pid)
)
),
array(
'$project' => array(
'pos' => 1,
'collat' => 1,
'locid' => 1
)
),
array(
'$match' => array(
'locid' => array('$in' => $ids)
)
),
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
)
)
)
);
$out = $myCollection->aggregate($ops);
Update This is the way I got it to group & return pos without throwing an error. I need to spot check it though to make sure it's actually returning the correct values though.
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
),
array('$min' => '$pos')
)
)
Aggregation query is like an SQL statement group by. You are telling {$group} what field(s) you want to 'GROUP BY' but you are not telling it how you want to aggregate the grouped information.
The {$group} you want is probably something like:
{$group : { _id : { locid: "$locid", collat: "$collat"},
pos : {$min : "$pos"}
}
}
I'm modifying an image upload extension and I'm working on a feature where images can be placed in categories.
Right now the categories are listed in a select field that uses foreign_table to get the categories from a table (called tx_gallery_categories) and when saved the category Id (the value in the option field) is saved to table called tx_gallery_items.
But that column is no longer needed (i was wrong the first time). Depending on what category you choose I want TCA to update a table called tx_gallery_itemsCategory and set the categoryId where itemId is equal to the saved images uid
Here is the TCA (i have removed all other columns beside categoryId) and categoryId is the one I want to move out from this, I think, and in to it's own TCA which is connected to tx_gallery_itemsCategory:
$TCA["tx_gallery_items"] = array (
"ctrl" => $TCA["tx_gallery_items"]["ctrl"],
"interface" => array (
"showRecordFieldList" => "hidden,oid,filename, videoembedcode,caption"
),
"feInterface" => $TCA["tx_gallery_items"]["feInterface"],
"columns" => array (
"categoryId" => Array (
"exclude" => 1,
"label" => "LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items.categories",
"config" => Array (
"type" => "select",
"foreign_table" => "tx_gallery_categories",
// "foreign_table_where" => " true"
// "itemsProcFunc" => "tx_gallery_getImageCategories->getCategories"
// 'default' => '123'
)
),
),
"types" => array (
"0" => array("showitem" => "hidden, oid, filename, categoryId, videoembedcode, caption, linkpid")
)
);
$TCA["tx_gallery_categories"] = array (
"ctrl" => $TCA["tx_gallery_categories"]["ctrl"],
"interface" => array (
"showRecordFieldList" => "categoryTitle"
),
"feInterface" => $TCA["tx_gallery_categories"]["feInterface"],
"columns" => array (
"categoryTitle" => Array (
"exclude" => 0,
"label" => "LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items.categories",
"config" => Array (
"type" => "text",
"cols" => "30",
"rows" => "5",
)
)
),
"types" => array (
"0" => array("showitem" => "categoryTitle")
)
);
But instead of it working like that I want to save the images uid from tx_gallery_items to another table called tx_gallery_itemsCategory which is a many to many table between tx_gallery_items and tx_gallery_categories
Here are the tables:
tx_gallery_items:
uid | pid | ... (and many more but only uid is relevant)
432 | 34 | ...
tx_gallery_itemsCategory:
id | itemId | categoryId
1 | 432 | 1
tx_gallery_categories:
uid | pid | categoryTitle
1 | 34 | example category
And here is the ext_tables.php
$TCA["tx_gallery_items"] = array (
"ctrl" => array (
'title' => 'LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items',
'label' => 'filename',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'sortby' => 'sorting',
'delete' => 'deleted',
'enablecolumns' => array (
'disabled' => 'hidden',
),
'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php',
'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_gallery_items.gif',
),
"feInterface" => array (
"fe_admin_fieldList" => "hidden, oid, filename, category, videoembedcode, caption, linkpid, categoryId",
)
);
$TCA["tx_gallery_categories"] = array (
"ctrl" => array (
'title' => 'LLL:EXT:gc_gallery/locallang_db.xml:tx_gallery_items',
'label' => 'categoryTitle',
'tstamp' => 'tstamp',
'sortby' => 'sorting',
'delete' => 'deleted',
// 'enablecolumns' => array (
// 'disabled' => 'hidden',
// ),
'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tca.php',
'iconfile' => t3lib_extMgm::extRelPath($_EXTKEY).'icon_tx_gallery_items.gif',
),
// "feInterface" => array (
// "fe_admin_fieldList" => "uid, pid, categoryTitle, categoryDescription, tstamp, sorting, deleted, hidden, categorySlug",
// )
);
So my question is (i think) how can I get the uid from the current image the user is editing and save it to another table.
This is my first try with TCA and I'm very confused on how all this is connected.
I hope that anyone knows this better than me :)
Thanks.
There is the hook concept implemented in the tcemain component. There is one called processDatamap_postProcessFieldArray which is invoked when any record is saved in the backend. Thus, you can check whether it's "yours" and do your other queries or whatever you want to change.
There is an example of how to use this feature. Although it is pretty old, it should still be working that way.
How I can modify nested array e.g.
`array (
'_id' => new MongoId("4e3a81376155a9d439000000"),
'name' => 'Umar',
'password' => 'rose',
'email' => 'umar#ibm.com',
'experience' =>
array (
0 =>
array (
'company' => 'ibm',
'from' => '2005',
'to' => '2007',
),
1 =>
array (
'company' => 'sun',
'from' => '2007',
'to' => '2009',
),
2 =>
array (
'company' => 'oracle',
'from' => '2009',
'to' => 'still',
),
),
)
`
Now i want to update company sun from value existing value is 2007 I want to change with 2006. I am using PHP.
Would you please help.
Best Regards,
Umar
Quite simply:
$yourArray["experience"][1]["from"] = 2006;