Cumulocity CEL Check if event exists - complex-event-processing

I am trying to implement that if I send Event A it will create a new Event B if it does not exist. If Event B already exists it should update it instead.
I tried making a counter that counts occurences of the event but it didnt work.
Also it seems that "not exists" should be implemented but I do not get it to work.
Thanks in advance Greets

If I got it well. Your are trying to create o update an event depend if an event with the same "key" exist.
One approach is to create your custom "key" like so:
insert into
CreateEvent
select
"testtype" as type,
part.event.source as source,
"testext" as text,
{
"mycustomkey" , "customValue",
} as fragments
from EventCreated;
Here we create an event with a custom key => "mycustomkey" with a custom value => "customValue".
Then when a new event is create you can use the "where" clause to know is you need to create a new event or update other event.
// create a new event if the firstEvent function return an event which
// the "mycustomkey" key if different to "customValue"
insert into
CreateEvent
select
"testtype" as type,
part.event.source as source,
"testext" as text,
{
"mycustomkey" , "customValue",
} as fragments
from EventCreated e
where getString(cast(
findFirstEventByFragmentTypeAndType("mycustomkey", "testtype"),
com.cumulocity.model.event),
"mycustomkey") != "customValue";
Here just update the event if the if the firstEvent function return an event which the "mycustomkey" if equal to "customValue"
insert into
EventUpdated
select
"testtype" as type,
part.event.source as source,
"testext" as text,
{
"mycustomkey" , "customValue",
} as fragments,
cast(findFirstEventByFragmentTypeAndType("mycustomkey",
"testtype"), com.cumulocity.model.event), "mycustomkey").getId() as
id
from EventCreated e
where getString(cast(
findFirstEventByFragmentTypeAndType("mycustomkey", "testtype"),
com.cumulocity.model.event),
"mycustomkey") = "customValue";
This solution needs that "customValue" must we know it and also the findFirstEventByFragmentTypeAndType function assumes it is going to return the event you need. We can improve this solution buy calling other function like findOneEventByFragmentType, findEventByFragmentTypeAndSourceAndTimeBetweenAndType etc..(you can find more information here) and find the event you need using a javascript function like :
insert into
CreateEvent
select
"testtype" as type,
part.event.source as source,
"testext" as text,
{
"mycustomkey" , "customValue",
} as fragments
from EventCreated e
where findTheCorrectEvent(
findEventByFragmentTypeAndSourceAndTimeBetweenAndType(
"mycusto mkey", "source", datefrom, dateTo).toJSON(),
"customValue") = true;
insert into
EventUpdated
select
"testtype" as type,
part.event.source as source,
"testext" as text,
{
"mycustomkey" , "customValue",
} as fragments
from EventCreated e
where findTheCorrectEvent(
findEventByFragmentTypeAndSourceAndTimeBetweenAndType(
"mycusto mkey", "source", datefrom, dateTo).toJSON(),
"customValue") = false;
create expression Boolean findTheCorrectEvent(evens, "customValue") [
var result = _findTheCorrectEvent(events, "customValue")
function _findTheCorrectEvent(events, referenceKey){
var _events = JSON.parse(events)
var result = false
_events.forEach(function(event){
if(event.mycustomkey === referenceKey) result = true
})
return result
}
result
];
Other approach, which in long term is easier, is create a microservice that do this. One microservice could check the last events created and check is the keys already exist and then update the same event otherwise create a new event.
In both solutions we need to create a "customkey" with a "customvalue" in other to find out if the event already exist. This "customkey" can be created using the a unique key like currentime which is a number.
Hope this can help you.
Good luck!

Related

Querying a many:many relationship on PK of the related table (ie. filtering by related table column)

I have a many:many relationship between 2 tables: note and tag, and want to be able to search all notes by their tagId. Because of the many:many I have a junction table note_tag.
My goal is to expose a computed field on my Postgraphile-generated Graphql schema that I can query against, along with the other properties of the note table.
I'm playing around with postgraphile-plugin-connection-filter. This plugin makes it possible to filter by things like authorId (which would be 1:many), but I'm unable to figure out how to filter by a many:many. I have a computed column on my note table called tags, which is JSON. Is there a way to "look into" this json and pick out where id = 1?
Here is my computed column tags:
create or replace function note_tags(note note, tagid text)
returns jsonb as $$
select
json_strip_nulls(
json_agg(
json_build_object(
'title', tag.title,
'id', tag.id,
)
)
)::jsonb
from note
inner join note_tag on note_tag.tag_id = tagid and note_tag.note_id = note.id
left join note_tag nt on note.id = nt.note_id
left join tag on nt.tag_id = tag.id
where note.account_id = '1'
group by note.id, note.title;
$$ language sql stable;
as I understand the function above, I am returning jsonb, based on the tagid that was given (to the function): inner join note_tag on note_tag.tag_id = tagid. So why is the json not being filtered by id when the column gets computed?
I am trying to make a query like this:
query notesByTagId {
notes {
edges {
node {
title
id
tags(tagid: "1")
}
}
}
}
but right now when I execute this query, I get back stringified JSON in the tags field. However, all tags are included in the json, whether or not the note actually belongs to that tag or not.
For instance, this note with id = 1 should only have tags with id = 1 and id = 2. Right now it returns every tag in the database
{
"data": {
"notes": {
"edges": [
{
"node": {
"id": "1",
"tags": "[{\"id\":\"1\",\"title\":\"Psychology\"},{\"id\":\"2\",\"title\":\"Logic\"},{\"id\":\"3\",\"title\":\"Charisma\"}]",
...
The key factor with this computed column is that the JSON must include all tags that the note belongs to, even though we are searching for notes on a single tagid
here are my simplified tables...
note:
create table notes(
id text,
title text
)
tag:
create table tag(
id text,
title text
)
note_tag:
create table note_tag(
note_id text FK references note.id
tag_id text FK references tag.id
)
Update
I am changing up the approach a bit, and am toying with the following function:
create or replace function note_tags(n note)
returns setof tag as $$
select tag.*
from tag
inner join note_tag on (note_tag.tag_id = tag.id)
where note_tag.note_id = n.id;
$$ language sql stable;
I am able to retrieve all notes with the tags field populated, but now I need to be able to filter out the notes that don't belong to a particular tag, while still retaining all of the tags that belong to a given note.
So the question remains the same as above: how do we filter a table based on a related table's PK?
After a while of digging, I think I've come across a good approach. Based on this response, I have made a function that returns all notes by a given tagid.
Here it is:
create or replace function all_notes_with_tag_id(tagid text)
returns setof note as $$
select distinct note.*
from tag
inner join note_tag on (note_tag.tag_id = tag.id)
inner join note on (note_tag.note_id = note.id)
where tag.id = tagid;
$$ language sql stable;
The error in approach was to expect the computed column to do all of the work, whereas its only job should be to get all of the data. This function all_nuggets_with_bucket_id can now be called directly in graphql like so:
query MyQuery($tagid: String!) {
allNotesWithTagId(tagid: $tagid) {
edges {
node {
id
title
tags {
edges {
node {
id
title
}
}
}
}
}
}
}

APEX Trigger when a textfield gets updated

I am trying to create a trigger in APEX, when an custom textfield of an custom sObject gets updated with products (means, when new products get insert or existing one get deleted).
How can I compare in APEX the Trigger.Old values with the Trigger? New values of this field in order to start the Trigger.
It would look something like this:
Trigger NameOfTrigger on CustomSObject__c (after update){
/*there is already an existing list of products that get insert into the custom textfield (probably as Strings)
*/
List <String> textList = new List <String> ();
/*PseudoCode: if the textfield got updated/has changed, copy from every entry of this textfield (entry = product name as a string) and copy fieldX into another sObject
*/
if(CustomSObject.field(OldValues) != CustomSObject.field(NewValues)){
for (String product : textList){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
Could somebody help me with the syntax?
You can utilize inbuilt Trigger.new and Trigger.old to get the latest and old values of any record. These lists can be used to achieve what you're looking for.
Sample example would be:
Trigger NameOfTrigger on CustomSObject__c (after update){
for(CustomSObject__c customObject : Trigger.new) {
// get old record
CustomSObject__c oldCustomObject = Trigger.oldMap.get(customObject.Id);
// compare old and new values of a particular field
if(customObject.fieldName != oldCustomObject.fieldName){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
}
}
See documentation of Trigger.new & Trigger.old

Apex code to update new Opportunity with values from related object

What would be the proper method to update a list of new Opportunities with the values from a related record.
for (Opportunity opps:Trigger.new){
[SELECT Id, CorpOwner__r, Contact__r,(SELECT Id, AccountLocation from Account)]
o.CorpOwner__r =Account.Id; o.AccountLocation = opps.Account.AccountLocation;
insert opps
Do you call the lookup fields by the __r suffix? Could you do a before insert operation and still look up the Opportunity.CorpOwner__r relationship to values in the CorpOwner__r Account record, or does that relationship not exist since the record has not been created? What would be a proper batchified way to go about it?
Here's a possibility that demonstrates a number of concepts:
trigger UpdateOpptyWithAccountInfo on Opportunity (before insert) {
// Keep this SOQL query out of the FOR loop for better efficiency/batching
Map<Id, Account> relatedAccounts = new Map<Id, Account>(
[SELECT Id, AccountLocation__c
FROM Account
WHERE Id IN
(SELECT AccountId
FROM Opportunity
WHERE Id = :Trigger.new)
]
);
for (Opportunity o : Trigger.new) {
/* Find each opportunity's Account in the map we queried for earlier
* Note: there's probably a more efficient way to use a Map of Opportunity IDs to Account objects...
* This works fine and could be more readable.
*/
for (Account a : relatedAccounts.values()) {
if (a.Id == o.AccountId) {
// Once you've found the account related to this opportunity, update the values
o.CorpOwner__c = a.Id;
o.AccountLocation__c = a.AccountLocation__c;
}
}
}
// We're still inside an `insert` trigger, so no need to call `insert` again.
// The new fields will be inserted along with everything else.
}
If you're establishing the relationship between objects, use the __c suffix:
o.CorpOwner__c = a.Id; // Associate Account `a` as Opportunity `o`'s CorpOwner
If you're looking up a field on a related object, then you would use __r:
System.debug(o.CorpOwner__r.Name); // Print Opportunity `o`'s CorpOwner's name

Apex Trigger to Update Lookup Field (Contact)

Need some advise on how to populate a lookup field (contact) via apex trigger
I've created a lookup field called Contact__c on Idea object.
I would like to populate the Contact__c with the createdby User if it was originated from the web (CreatedBy.Contact.Account.Name == "Web Ideas") and leave it empty for internal idea creation.
I have read up and created the following trigger and was able to save and run. However, upon saving the idea record, i am getting an error : UpdateContactonComplaints: data changed by trigger for field Contact: id value of incorrect type: 005N0000000l9iMIAQ
trigger UpdateContactonComplaints on Idea (before insert, before Update) {
list<id> oid = new list<id>();
for(Idea o: trigger.new){
oid.add(o.id);
}
map<id, Idea> ExtendU = new map<id, Idea>(
[select CreatedbyID from Idea where id in: oid]);
for(Idea o: trigger.new){
o.Contact__c = ExtendU.get(o.id).CreatedbyID;
}
}
In the Trigger, the user id(id of the User who created the idea) is assigned to Contact custom lookup field).
So, it throws an error, data changed by trigger for field Contact: id value of incorrect type:

Trigger to update a custom lookup field on opportunity

I created a custom object XtendedUser which has an id and Name.
I created a custom lookupfield on Opportunity called "XtendedUser__c" which links the opportunity to the corresponding XtendedUser record.
Now I made it so that the name of an opportunityowner corresponds to the name of an XtendedUser-record, so I want the trigger to autopopulate the custom lookup field "XtendedUser__c" on the opportunity with the id of the corresponding XtendedUser-record of which the name matches the name of the opportunityowner.
I never wrote a trigger, always worked with workflows and fieldupdates, but I've got to make this work. So if you could please help me with this? I would be extremely greatfull!
Thanks in advance
You should use a map to link the records and retrieve the value before the insert of a new record and before the update of an existing record. This technique will also allow you to bulk update all your records. It should be something like:
trigger ExtendedUser__c on Opportunity (before insert, before Update) {
list<id> oid = new list<id>();
for(opportunity o: trigger.new){
oid.add(o.id);
}
map<id, ExtendedUser__c> ExtendU = new map<id, ExtendedUser__c>(
[select name from ExtendedUser__c where id in: oid]);
for(opportunity o: trigger.new){
o.name = ExtendU.get(o.id).name;
}
}