How to Perform UPSERT Operation in Arango DB with Different multiple keys (Composite Key)? - arangodb

In official documentations, it's already shown how to do that. Below, an example that working fine:
Example: 1
LET documents = [
{ name: 'Doc 1', value: 111, description: 'description 111' },
{ name: 'Doc 2', value: 222, description: 'description 2' },
{ name: 'Doc 3', value: 333, description: 'description 3' }
]
FOR doc IN documents
UPSERT { name: doc.name, description: doc.description }
INSERT doc
UPDATE doc
IN MyCollection
But, I want to check different multiple keys for each document on UPSERT, like:
Example: 2
LET documents = [
{ name: 'Doc 1', value: 777, description: 'description 111' },
{ name: 'Doc 2', value: 888, description: 'description 2' },
{ name: 'Doc 3', value: 999, description: 'description 3' }
]
FOR doc IN documents
UPSERT {
{ name: doc.name, description: doc.description },
{ value: doc.value, description: doc.description },
{ name: doc.name, value: doc.value }
}
INSERT doc
UPDATE doc
IN MyCollection
Or, any other other way (using filter or something). I had tried but nothing works

If I understand your problem, you would want to update a document, if there's an existing one with at least 2 fields matching, otherwise insert it as new.
UPSERT won't be able to do that. It can only do one match. So a subquery is necessary. In the solution below, I ran a query to find the key of the first document that matches at least 2 fields. If there's no such document then it will return null.
Then the UPSERT can work by matching the _key to that.
LET documents = [
{ name: 'Doc 1', value: 777, description: 'description 111' },
{ name: 'Doc 2', value: 888, description: 'description 2' },
{ name: 'Doc 3', value: 999, description: 'description 3' }
]
FOR doc IN documents
LET matchKey= FIRST(
FOR rec IN MyCollection
FILTER (rec.name==doc.name) + (rec.value==doc.value) + (rec.description==doc.description) > 1
LIMIT 1
RETURN rec._key
)
UPSERT {_key:matchKey}
INSERT doc
UPDATE doc
IN MyCollection
Note: There's a trick with adding booleans together which works because true will be converted to 1, while false is zero. You can write it out explicitly like this: (rec.name==doc.name?1:0)
While this will work for you it's not a very effective solution. Actually there's no effective one in this case because all the existing documents need to be scoured through to find a matching one, for each document to be added/updated. I'm not sure what kind of problem you are trying to solve with this, but it might be better to re-think your design so that the matching condition could be more simple.

Related

ArangoDB Retrieve parent object based on multiple filters on children properties

I have a Person object as follows
{
name: 'John Doe'
properties:
[
{
name: 'eyeColor',
value: 'brown'
},
{
name: 'age',
value: 25
},
{
name: 'interest',
value: 'reading'
},
{
name: 'interest',
value: 'diving'
}
]
}
Now I want to be able to filter my object based on multiple properties. In pseudocode:
Return all people for which
there exists any p.property such that
p.property.propertyname == 'interest'
AND p.property.propertyvalue == 'reading'
AND there exists any p.property such that
p.property.propertyname == 'age'
AND p.property.propertyvalue < 30
What is the most concise and extensible (I want to be able to apply N of these filters) of doing this without having too many intermediate results?

How to create an index for partial text search on MongoDB?

I'm following the tutorial instruction: https://docs.mongodb.com/manual/core/index-text/
This is the sample data:
db.stores.insert(
[
{ _id: 1, name: "Java Hut", description: "Coffee and cakes" },
{ _id: 2, name: "Burger Buns", description: "Gourmet hamburgers" },
{ _id: 3, name: "Coffee Shop", description: "Just coffee" },
{ _id: 4, name: "Clothes Clothes Clothes", description: "Discount clothing" },
{ _id: 5, name: "Java Shopping", description: "Indonesian goods" }
]
)
Case 1: db.stores.find( { $text: { $search: "java coffee shop" } } ) => FOUND
Case 2: db.stores.find( { $text: { $search: "java" } } ) => FOUND
Case 3: db.stores.find( { $text: { $search: "coff" } } ) => NOT FOUND
I'm expecting case 3 is FOUND because the query is matches a part of java coffee shop
Case 3 will not work with $text operator and reason is how Mongo Creates Text Indexes.
Mongo takes text indexed fields values and creates separate indexes for each unique word in string and not character(!).
so this means, that in your case for 1 object:
field name will have 2 indexes:
java
hut
field description will have 3 indexes:
coffee
and
cakes
$text operator compare $search values with this indexes and that's why "coff" will not work.
If you strongly want to take advantages of indexes you have to use $text operator, but it does not give you all flexibility, just like you want.
solution:
You Can simply use $regex with case sensitiveness option (i) and optimize your query with skip and limit.
If you want to return all documents and collection is large, $regex will cause performance issue
you can also check this article https://medium.com/coding-in-depth/full-text-search-part-1-how-to-create-mongodb-full-and-partial-text-search-c09c0bae17a3 and maybe use wildcard indexes for that, but i do not know is it a good practice or not.

How does MongoDB $text search works?

I have inserted following values in my events collection
db.events.insert(
[
{ _id: 1, name: "Amusement Ride", description: "Fun" },
{ _id: 2, name: "Walk in Mangroves", description: "Adventure" },
{ _id: 3, name: "Walking in Cypress", description: "Adventure" },
{ _id: 4, name: "Trek at Tikona", description: "Adventure" },
{ _id: 5, name: "Trekking at Tikona", description: "Adventure" }
]
)
I've also created a index in a following way:
db.events.createIndex( { name: "text" } )
Now when I execute the following query (Search - Walk):
db.events.find({
'$text': {
'$search': 'Walk'
},
})
I get these results:
{ _id: 2, name: "Walk in Mangroves", description: "Adventure" },
{ _id: 3, name: "Walking in Cypress", description: "Adventure" }
But when I search Trek:
db.events.find({
'$text': {
'$search': 'Trek'
},
})
I get only one result:
{ _id: 4, name: "Trek at Tikona", description: "Adventure" }
So my question is why it dint resulted:
{ _id: 4, name: "Trek at Tikona", description: "Adventure" },
{ _id: 5, name: "Trekking at Tikona", description: "Adventure" }
When I searched walk it resulted the documents containing both walk and walking. But when I searched for Trek it only resulted the document including trek where it should have resulted both trek and trekking
MongoDB text search uses the Snowball stemming library to reduce words to an expected root form (or stem) based on common language rules. Algorithmic stemming provides a quick reduction, but languages have exceptions (such as irregular or contradicting verb conjugation patterns) that can affect accuracy. The Snowball introduction includes a good overview of some of the limitations of algorithmic stemming.
Your example of walking stems to walk and matches as expected.
However, your example of trekking stems to trekk so does not match your search keyword of trek.
You can confirm this by explaining your query and reviewing the parsedTextQuery information which shows the stemmed search terms used:
db.events.find({$text: {$search: 'Trekking'} }).explain().queryPlanner.winningPlan.parsedTextQuery
{
​ "terms" : [
​ "trekk"
​ ],
​ "negatedTerms" : [ ],
​ "phrases" : [ ],
​ "negatedPhrases" : [ ]
}
You can also check expected Snowball stemming using the online Snowball Demo or by finding a Snowball library for your preferred programming language.
To work around exceptions that might commonly affect your use case, you could consider adding another field to your text index with keywords to influence the search results. For this example, you would add trek as a keyword so that the event described as trekking also matches in your search results.
There are other approaches for more accurate inflection which are generally referred to as lemmatization. Lemmatization algorithms are more complex and start heading into the domain of natural language processing. There are many open source (and commercial) toolkits that you may be able to leverage if you want to implement more advanced text search in your application, but these are outside the current scope of the MongoDB text search feature.

Creating NetSuite Saved Searches with Multiple Line Items

I'm working on a NetSuite Saved Search using Kit/Package (Item) records that have multiple line items. For instance, each Kit/Package is comprised of two Item SKUs.
At the moment, my Saved Search is pulling in each Item SKU on its own individual line. How can I keep each Kit/Package on one line with the different Item SKUs pulled into their own columns? Can I create one column that always pulls in Item SKU #1 and another that always pulls in Item SKU #2?
The record I am looking to pull in is {memberitem}. Is there a way to tell it to pull in {memberitem}, {memberitem1}, and {memberitem2} into different columns?
First of all - the only way I see to have a search combining 2 member items on one row is to group the fields, i.e. - to create a summary search.
If you need this search to be used as a base for Advanced PDF Template, the only way is to write a script (as the summary Searches are not allowed in Advanced PDF/HTML templates).
Here I have created for you a suitelet script, that perform this PDF generation. Of course I have the xml inside the code, but you could load the pre-saved XML file from the file cabinet. Also, you could create a saved search and just load it in the script. Keep in mind that all the fields at ITEM level should be with summary type "GROUP"
/**
* #NApiVersion 2.x
* #NScriptType Suitelet
* #NModuleScope SameAccount
*/
define(['N/render','N/search'],
function(render, search) {
function onRequest(context) {
var kititemSearchObj = search.create({
type: "kititem",
filters: [
["type","anyof","Kit"]
],
columns: [
search.createColumn({
name: "itemid",
summary: "GROUP"
}),
search.createColumn({
name: "displayname",
summary: "GROUP"
}),
search.createColumn({
name: "salesdescription",
summary: "GROUP"
}),
search.createColumn({
name: "baseprice",
summary: "GROUP"
}),
search.createColumn({
name: "formulatext",
summary: "MAX",
formula: "CASE WHEN {memberline}=1 THEN {memberitem} ELSE null END"
}),
search.createColumn({
name: "formulatext",
summary: "MAX",
formula: "CASE WHEN {memberline}=2 THEN {memberitem} ELSE null END"
})
]
});
var myCustomObject = {
KitItems : []
};
kititemSearchObj.run().each(function(r){
var aRow = {
linenum : myCustomObject.KitItems.length + 1,
itemid : r.getValue({
name: "itemid",
summary: "GROUP"
}),
displayname : r.getValue({
name: "displayname",
summary: "GROUP"
}),
salesdescription : r.getValue({
name: "salesdescription",
summary: "GROUP"
}),
baseprice : r.getValue({
name: "baseprice",
summary: "GROUP"
}),
memberitem1 : r.getValue({
name: "formulatext",
summary: "MAX",
}),
memberitem2 : r.getValue({
name: "formulatext_1",
summary: "MAX",
})
};
myCustomObject.KitItems.push(aRow);
return true;
});
var renderer = render.create();
var xmlStr =
'<?xml version="1.0"?>\n'+
'<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">\n' +
'<pdf>\n<body size="A4">\n'+
'<#if results.KitItems?has_content>'+
'<table><!-- start rows --><#list results.KitItems as line>'+
' <tr><td>${line.linenum}</td>'+
' <td>${line.itemid}</td>'+
' <td>${line.displayname}</td>'+
' <td>${line.salesdescription}</td>'+
' <td>${line.baseprice}</td>'+
' <td>${line.memberitem1}</td>'+
' <td>${line.memberitem2}</td>'+
' </tr>'+
' </#list>'+
'</table>'+
'</#if>'+
'</body>\n</pdf>';
renderer.templateContent = xmlStr;
renderer.addCustomDataSource({
format: render.DataSource.OBJECT,
alias: "results",
data: myCustomObject
});
var pdfResult = renderer.renderAsPdf();
pdfResult.name = 'kitItems.pdf';
context.response.writeFile({
file: pdfResult,
isInline : true
});
}
return {
onRequest: onRequest
};
});

Get value from results which be query from collection in MongoDB

When I query from collection in MongoDB and it has results:
[ { details:
[ { owner: '57f52829bcc705bb1c37d611',
nameprd: 'fsfsdaf',
price: 15000000,
descrice: 'sfsdfsdaf',
number: 4,
dateOff: '2016-06-12T17:00:00.000Z',
_csrf: 'CPlxeLpq-vYfTTWTgSpR6bsyapbDVgDCKzTc',
image: 'samsung-galaxy-note-7.png',
createdAt: '2016-10-06T16:43:11.109Z',
updatedAt: '2016-10-06T16:43:13.061Z',
id: '57f67f1f7ab99e5824652208' } ],
name: 'Máy tính bảng',
_csrf: 'Ze6OhtgL-2hZvG7TuP9NO4fjY90rA7x46bWA',
createdAt: '2016-10-05T16:19:53.331Z',
updatedAt: '2016-10-06T16:43:13.021Z',
id: '57f52829bcc705bb1c37d611' },
]
Now, how to get value which called details in this result.
Thanks.
You should add the query the following syntax: ,{'details':1}
For example:
If that is the original query:
db.person.find({'name':'joe'})
Than the following query returns only the details value of the query:
db.person.find({'name':'joe'},{'details':1})
The addition of the ,{'details':1} means that you want to get only the data for the details. It is uses as a filter to the extensive query.

Resources