Retrieve elements from MongoDB - arrays

I've been looking at some StackOverflow cases such as this case, but I cannot find an example with a document structure close to this one.
Below is an example of one document within my collection artistTags. All documents follow the same structure.
{
"_id": ObjectId("5500aaeaa7ef65c7460fa3d9"),
"toptags": {
"tag": [
{
"count": "100",
"name": "Hip-Hop"
},
{
"count": "97",
"name": "french rap"
},
...{
"count": "0",
"name": "seen live"
}
],
"#attr": {
"artist": "113"
}
}
}
1) How can I find() this document using the "artist" value (here "113")?
2) How can I retrieve all "artist" values having a specific "name" value (say "french rap") ?

Referring to chridam answer here above:
db.collection.find({"toptags.#attr.artist": "113"})

Related

Solr - Search parent having multiple child documents

I have a Solr index with structure as below.
{
"id": "1",
"bookName_s": "Core Concepts",
"bookDescription_s": "This is the description",
"isbn_s": "ABCD:123",
"reviews": [
{
"id": "2",
"Name_s": "review1",
"detail_s": "sample review"
}
],
"students": [
{
"id": "3",
"Name_s": "student1",
"student_s": "test student"
}
]
}
How do i search for parent that has a reviewer with Name_s as 'review1' and student with Name_s as 'student'.
I tried parent block chain query like below but nothing seems to work -
q=({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/reviews +Name_s:*rev*)) AND ({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/students +Name_s:*stu*))
q=({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/reviews +Name_s:*rev*)(+_nest_path_:\/students +Name_s:*stu*))
Is there a way i can acheive this using the q operator instead of fq parameter? thanks
Based on EricLavault suggestion i modified the index to include type of the object in the index like below -
{
"id": "1",
"bookName_s": "Core Concepts",
"bookDescription_s": "This is the description",
"isbn_s": "ABCD:123",
"type_s":"book"
"reviews": [
{
"id": "2",
"Name_s": "review1",
"detail_s": "sample review",
"type":"review"
}
],
"students": [
{
"id": "3",
"Name_s": "student1",
"type":"student",
"student_s": "test student"
}
]
}
and below queries worked.
{!parent which="type:book"}(type:review AND Name_s:review1) OR (type:student AND Name_s:student1)
returns all books with review1 and student1

How to update array inside MongoDB document

Can someone help me with a solution to update an array object inside the MongoDB document, I've tried a couple of methods but still it's to updating, here is my document that I want to update the array in the document.
{
"title": "Products",
"description": "test",
"image": "bdd8510d75f6e83ad308d5f306afccef_image.jpg",
"_created_at": "2021-06-07T20:51:08.316Z",
"ratingCount": 0,
"ratingTotal": 0,
"placeListSave": [
{
"objectId": "g70brr45pfi",
"name": "Kale",
"email": "null",
"strBrandLogo": "84de8865e3223d1ca61386355895aa04_image.jpg",
"storeNumber": "56",
"phone": "0815342119",
"createdAt": "2021-06-10T10:19:53.384Z",
"image": "ad1fb7602c2188223fd891a52373cb9d_image.jpg"
},
{
"objectId": "0qokn33p773",
"name": "Apple",
"email": null,
"strBrandLogo": null,
"storeNumber": "01",
"phone": "011 393 8600",
"createdAt": "2021-06-11T03:11:17.342Z",
"image": "8cfcbf2bcb5e3b4ea8ade44d3825bb52_image.jpg"
}
]
}
So I only want to update the apple object and change the data, I've tried the following code but doesn't seem to work.
`
var db = client.db("test");
try {
db.collection("ShoppingCentres").updateOne({
"title": req.body.product,
"placeListSave.objectId": req.body.id,
}, {
$set: {
"placeListSave.$.email": req.body.email,
"placeListSave.$.storeNumber": req.body.storeNumber,
"placeListSave.$.phone": req.body.phone,
"placeListSave.name": req.body.name,
},
});
res.json("client");
} catch (e) {
console.log("verify", e);
}
});`
arrayFilters seems suitable here:
db.collection.update({
"title": "Products",
"placeListSave.objectId": "0qokn33p773",
},
{
$set: {
"placeListSave.$[x].email": "test#some.email",
"placeListSave.$[x].storeNumber": "test",
"placeListSave.$[x].phone": "test",
"placeListSave.$[x].name": "test"
}
},
{
arrayFilters: [
{
"x.objectId": "0qokn33p773"
}
]
})
explained:
Add array filter called "x" with the objectId for the element that you need to update and use this filter in the $set stage to update the necessary elements.
Hint: To speed up the update you will need to add index on title field or compound index on title+placeListSave.objectId
playground

Is it possible to apply a solr document int field value as boost value if a specific field is matched?

Ex.
"docs": [
{
"id": "f37914",
"index_id": "some_index",
"field_1": [
{
"Some value",
"boost": 20.
}
]
},
]
If 'field_1' is matched, then boost by corresponding 'boost' field.
Boost what? the document? the specific field? you can do any of them.
Anyway the way to do it is to user Function Queries:
https://lucene.apache.org/solr/guide/6_6/function-queries.html#FunctionQueries-AvailableFunctions
For example if you want to boost the document (and assuming if the value doesn't match then the score is 0) then you can do something like that:
q:_val_:"if(query($q1), field(boost), 0)"&q1=field_1:"Some Value"
_val_ is just a hook into Solr function query, query returns true if q1 matches, field is a simple function that just return the value of the field it self and if allows us to join the two together.
So what I ended up doing is using lucence payloads and solr 6.6 new DelimitedPayloadTokenFilter feature.
First I created a terms field with the following configuration:
{
"add-field-type": {
"name": "terms",
"stored": "true",
"class": "solr.TextField",
"positionIncrementGap": "100",
"indexAnalyzer": {
"tokenizer": {
"class": "solr.KeywordTokenizerFactory"
},
"filters": [
{
"class": "solr.LowerCaseFilterFactory"
},
{
"class": "solr.DelimitedPayloadTokenFilterFactory",
"encoder": "float",
"delimiter": "|"
}
]
},
"queryAnalyzer": {
"tokenizer": {
"class": "solr.KeywordTokenizerFactory"
},
"filters": [
{
"class": "solr.LowerCaseFilterFactory"
},
{
"class": "solr.SynonymGraphFilterFactory",
"ignoreCase": "true",
"expand": "false",
"tokenizerFactory": "solr.KeywordTokenizerFactory",
"synonyms": "synonyms.txt"
}
]
}
},
"add-field" : {
"name":"terms",
"type":"terms",
"stored": "true",
"multiValued": "true"
}
}
I indexed my documents likes so:
[
{
"id" : "1",
"terms" : [
"some term|10.0",
"another term|60.0"
]
}
,
{
"id" : "2",
"terms" : [
"some term|11.0",
"another term|21.0"
]
}
]
I used solr's functional query support to query for a match on terms and grab the attached boost payload and apply it to the relevancy score:
/solr/payloads/select?indent=on&wt=json&q={!payload_score%20f=ai_terms_wtih_synm_3%20v=$payload_term%20func=max}&fl=id,score&payload_term=some+term

Unique Filter to Elastic Search Column not working (duplicate items inserted)

I've modified my contactNumber field to have a unique filter
by updating the index settings as follows
curl -XPUT localhost:9200/test-index2/_settings -d '
{
"index":{
"analysis":{
"analyzer":{
"unique_keyword_analyzer":{
"only_on_same_position":"true",
"filter":"unique"
}
}
}
},
"mappings":{
"business":{
"properties":{
"contactNumber":{
"analyzer":"unique_keyword_analyzer",
"type":"string"
}
}
}
}
}'
A sample Item looks like this,
doc_type:"Business"
contactNumber:"(+12)415-3499"
name:"Sam's Pizza"
address:"Somewhere on earth"
The Filter does not work, as duplicate items are inserted, I'd like NO two documents having the same contactNumber
in the above, I've also set only_on_same_position -> true so that existing duplicate values would be truncated/deleted
What am i doing wrong in the settings?
That's something Elasticsearch couldn't help you out of the box... you need to make this uniqueness functionality available in your app. The only idea that I can think of is to have the phone number as the _id of the document itself and whenever you insert/update something ES will use the contactNumber as _id and it will associate that document with the one that already exists or create a new one.
For example:
PUT /test-index2
{
"mappings": {
"business": {
"_id": {
"path": "contactNumber"
},
"properties": {
"contactNumber": {
"type": "string",
"analyzer": "keyword"
},
"address": {
"type": "string"
}
}
}
}
}
Then you index something:
POST /test-index2/business
{
"contactNumber": "(+12)415-3499",
"address": "whatever 123"
}
Getting it back:
GET /test-index2/business/_search
{
"query": {
"match_all": {}
}
}
It looks like this:
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_score": 1,
"_source": {
"contactNumber": "(+12)415-3499",
"address": "whatever 123"
}
}
]
}
You see there that the _id of the document is the phone number itself. If you want to change or insert another document (the address is different, there is a new field - whatever_field - but the contactNumber is the same):
POST /test-index2/business
{
"contactNumber": "(+12)415-3499",
"address": "whatever 123 456",
"whatever_field": "whatever value"
}
Elasticserach "updates" the existing document and responds back with:
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_version": 2,
"created": false
}
created is false, this means the document has been updated, not created. _version is 2 which again says that the document has been updated. And the _id is the phone number itself which indicate this is the document that has been updated.
Looking again in the index, ES stores this:
"hits": [
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_score": 1,
"_source": {
"contactNumber": "(+12)415-3499",
"address": "whatever 123 456",
"whatever_field": "whatever value"
}
}
]
So, the new field is there, the address has changed, the contactNumber and _id are exactly the same.

Insert object in nested array mongodb nodejs

So I am trying to insert an object in parameters and have been unsuccessful. My mongodb structure looks like this:
[
{
"_id": "04",
"name": "test service 4",
"id": "04",
"version": "0.0.1",
"title": "testing",
"description": "test",
"protocol": "test",
"operations": [
{
"_id": "99",
"oName": "test op 52222222222",
"sid": "04",
"name": "test op 52222222222",
"oid": "99",
"parameters": {},
"description": "testing",
"returntype": "test"
},
{
"_id": "58",
"oName": "test op 52222222222",
"sid": "04",
"name": "test op 52222222222",
"oid": "58",
"parameters": {},
"description": "testing",
"returntype": "test"
}
]
}
]
I want to be able to add an object into parameters with basic details such as name, id, and type. I am not entirely sure how to tackle this as I have all other CRUD operations implemented up until the parameters part. How should I go about to complete this? I know mongodb has issues when trying to insert something into an array inside an array, so if anyone has any suggestions as to how I can complete this I would really appreciate it. Thanks.
One of the problems is I do not have access to the _id of the root object, but I do have the _id for the operation where I am inserting the parameter. Hence I was trying to insert the parameter using this code:
collection.update({"operations":{"$elemMatch": {"oid": oid}}}, {'$addToSet':{"operations.parameters": {name: "test"} }}, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.send(result[0]);
}
});
This does not work though.
I was able to complete the insert by using the following code:
collection.update({ "operations": {$elemMatch: {_id:oid}}}, {$addToSet: { "operations.$.parameters" : parameter}}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.send(result[0]);
}
});
Just in case anyone needed it.
This is because you need to use positional operator, The example I am copying from the link is almost the same as in your case:
db.students.update(
{ _id: 4, "grades.grade": 85 },
{ $set: { "grades.$.std" : 6 } }
)

Resources