In Azure search, is it possible to select objects in an array (Collection(Edm.ComplexType) field) which satisfy a predicate?
Using the any operator specified at https://learn.microsoft.com/en-us/azure/search/search-query-understand-collection-filters#correlated-versus-uncorrelated-search returns the entire root object if any of the objects in the array satisfies the predicate.
Example, given the object below in Azure search:
{
"arrayOfObjects": [
{
"id": 1,
"foo": "a"
},
{
"id": 2,
"foo": "b"
},
{
"id": 3,
"foo": "b"
}
]
}
Is it possible to select only the nested objects where foo equals “b”, so that the search response looks like this:
{
"arrayOfObjects": [
{
"id": 2,
"foo": "b"
},
{
"id": 3,
"foo": "b"
}
]
}
No, this is not possible. Queries in Azure Search operate at the granularity of documents, not objects within documents. A possible workaround would be to model your index such that the individual objects become top-level documents.
Related
I work on a project where the output of one of our APIs is a JSON array. I'd like to encapsulate this array inside an object.
I try to use a JOLT transformation (this is the first time I use this tool) to achieve this. I've already searched through a lot of example, but I still can't figure out what my JOLT specification has to be to perform the transformation. I can't find what I am looking for.
For example, if my input is like this:
[
{
"id": 1,
"name": "foo"
},
{
"id": 2,
"name": "bar"
}
]
I'd like the output to be:
{
"list":
[
{
"id": 1,
"name": "foo"
},
{
"id": 2,
"name": "bar"
}
]
}
In short, I just want to put my array inside a field of another object.
You can use a shift transformation spec such as
[
{
"operation": "shift",
"spec": {
"*": "list[]"
}
}
]
where "*" wildcard represents indices of the current wrapper array of objects
the demo on the site http://jolt-demo.appspot.com/ is
I have a collection like below
{
"doc_id": "1234",
"items": [
{
"item_no": 1,
"item": "car",
},
{
"item_no": 2,
"item": "bus",
},
{
"item_no": 3,
"item": "truck",
}
]
},
I need to update an element inside items list based on a search criteria. My search criteria is, if "item_no" is 3, "item" should be updated to "aeroplane".
I have written the following two approaches in Python to solve this.
Approach 1:
cursor = list(collection.find({"doc_id": 1234}))
for doc in cursor:
if "items" in doc:
temp = deepcopy(doc["items"])
for element in doc["items"]:
if ("item_no" and "item") in element:
if element["item_no"] == 3:
temp[temp.index(element)]["item"] = "aeroplane"
collection.update_one({"doc_id": 1234},
{"$set": {"items": temp}})
Approach 2:
cursor = list(collection.find({"doc_id": 1234}))
for doc in cursor:
if "items" in doc:
collection.find_one_and_update({"doc_id": 1234}, {'$set': {'items.$[elem]': {"item_no": 3, "item": "aeroplane"}}}, array_filters=[{'elem.item_no': {"$eq": 3}}])
Among the above two approaches, which one is better in terms of time complexity?
Use only a query and avoid loops:
db.collection.update({
"doc_id": "1234",
"items.item_no": 3
},
{
"$set": {
"items.$.item": "aeroplane"
}
})
Example here
Note how using "items.item_no": 3 into the find stage you can use $ into update stage to refer the object into the array.
So, doing
{
"doc_id": "1234",
"items.item_no": 3
}
When you use $ you are telling mongo: "Ok, do your action in the object where the condition is match" (i.e., the object in the collection with doc_id: "1234" and an array with items.item_no: 3)
Also if you want to update more than one document you can use multi:true like this example.
Edit: It seems you are using pymongo so you can use multi=True (insted of multi: true) or a cleaner way, using update_many.
collection.update_many( /* your query here */ )
I'm using mongodb to store my data. My collection consists in a list of objects identified by a type a list of other objects for each of them.
An example of my collection is:
[
{
"type": "a",
"properties": [
{
"value": "value_a",
"date": "my_date_a"
},
{
"value": "value_b",
"date": "my_date_b"
},
...
]
},
...
]
Based on the above data structure, I want to retrieve all collections by a given type, taking for each of them only one element in the nested array (reducing the nested list to a list of only one element).
So, given a type "a", an example of the result may be:
[
{
"type": "a",
"properties": [
{
"value": "value_a",
"date": "my_date_a"
}
]
},
...
]
I'm started trying this query { "type": "a" } to filter the collections. But, how can I do to take only one "properties" element? I cannot use the "slice" operator.
Thanks a lot.
I'm assuming from your reference to slice, that you're not interested in matching a particular nested element, and rather just getting a value at a fixed index (eg, 0).
If you're willing to use the aggregation pipeline, you can use arrayElementAt within a projection:
db.collection.aggregate([
// matches documents with type 'a'
{ $match: { type: 'a' } },
// creates a new document for each
{ $project: {
// that contains the original value for type
type: 1,
// and the first element from the original properties for properties
properties: { $arrayElemAt: [ "$properties", 0 ] }
} }
])
I am interested in storing key-value pair of metadata inside a JSON array containing multiple JSON objects. This will instruct a generic parser what to do with the list of JSON objects in the JSON Array when it is processing the JSON Array. Below is a sample JSON, with where I am hoping to have some sort of metadata field.
{
"Data": [
<< "metadata":"instructions" here >>
{
"foo": 1,
"bar": "barString"
},
{
"foo": 3,
"bar": "fooString"
}
]
}
What is the proper way to structure this mixed data JSON array?
I would add a meta key as a peer of data like below. This would separate your data from the meta data.
{
"Meta": {
"metadata":"instructions"
},
"Data": [
{
"foo": 1,
"bar": "barString"
},
{
"foo": 3,
"bar": "fooString"
}
]
}
If you can modify the structure of the data, why not add a property meta with your instructions (i.e. Data.meta) and another property content (for want of a better word...) (i.e. Data.content), where the latter is the original array of objects.
That way, it is still valid JSON, and other implementations can read the meta-field as well without much ado.
Edit: just realized, you would also have to make Data an object rather than array. Then your JSON-schema should become this:
{
"Data": {
"metadata": "instructions here",
"content": [
{
"foo": 1,
"bar": "barString"
},
{
"foo": 3,
"bar": "fooString"
}
]
}
}
This will probably be the most stable, maintainable and portable solution.
For refrence, something similar has already been asked before.
After some additional discussion with another developer, we thought of one way to include the metadata instructions in the data JSON array.
{
"Data": [
{
"metadata": "Instructions"
}
{
"foo": 1,
"bar": "barString"
},
{
"foo": 3,
"bar": "fooString"
}
]
}
This approach does come with the limitation that index 0 of the data JSON array MUST contain a JSON Object containing the metadata and associated instructions for the generic parser. Failure to include this metadata object as index 0 would trigger an error case that the generic parser would need to handle. So it does have its trade-offs.
I will go to try help you..
"metadata" : [
{
"foo": 1,
"bar": "barString"
},
{
"foo": 3,
"bar": "fooString"
}
]
Hi currently I want to sort array of object, I use ARRAY_SORT function, it will use the first field of object to sort & it work well if every object has the same JSON structure. If one element in array has different JSON structure, the result is incorrect.
The query I use :
SELECT ARRAY_SORT(c.student) as student FROM Class c
Result :
"student": [
{
"id": 3,
"name": "Kenny35"
},
{
"id": 6,
"name": "Kenny35"
},
{
"id": 7,
"name": "Kenny35"
},
{
"id": 8,
"name": "Kenny35"
},
{
"hobby": "video game",
"id": 5,
"name": "Kenny35"
}
]
How can I specify property of object in array for ARRAY_SORT function ?
dev,
Objects are first compared by length/size of the object, then followed by fields in the object.
http://developer.couchbase.com/documentation/server/4.5/n1ql/n1ql-language-reference/comparisonops.html
That is the only collation supported now.
-Prasad
You can issue a query and use ORDER BY.
SELECT *
FROM Class c
UNNEST c.student s
ORDER BY ...