I have a document that has an array:
{
_id: ObjectId("515e10784903724d72000003"),
association_chain: [
{
name: "Product",
id: ObjectId("4e1e2cdd9a86652647000003")
}
],
//...
}
I'm trying to search the collection for documents where the name of the first item in the association_chain array matches a given value.
How can I do this using Mongoid? Or if you only know how this can be done using MongoDB, if you post an example, then I could probably figure out how to do it with Mongoid.
Use the positional operator. You can query the first element of an array with .0 (and the second with .1, etc).
> db.items.insert({association_chain: [{name: 'foo'}, {name: 'bar'}]})
> db.items.find({"association_chain.0.name": "foo"})
{ "_id" : ObjectId("516348865862b60b7b85d962"), "association_chain" : [ { "name" : "foo" }, { "name" : "bar" } ] }
You can see that the positional operator is in effect since searching for foo in the second element doesn't return a hit...
> db.items.find({"association_chain.1.name": "foo"})
>
...but searching for bar does.
> db.items.find({"association_chain.1.name": "bar"})
{ "_id" : ObjectId("516348865862b60b7b85d962"), "association_chain" : [ { "name" : "foo" }, { "name" : "bar" } ] }
You can even index this specific field without indexing all the names of all the association chain documents:
> db.items.ensureIndex({"association_chain.0.name": 1})
> db.items.find({"association_chain.0.name": "foo"}).explain()
{
"cursor" : "BtreeCursor association_chain.0.name_1",
"nscanned" : 1,
...
}
> db.items.find({"association_chain.1.name": "foo"}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 3,
...
}
Two ways to do this:
1) if you already know that you're only interested in the first product name appearing in "association_chain", then this is better:
db.items.find("association_chain.0.name":"something")
Please note that this does not return all items, which mention the desired product, but only those which mention it in the first position of the 'association_chain' array.
If you want to do this, then you'll need an index:
db.items.ensureIndex({"association_chain.0.name":1},{background:1})
2) if you are looking for a specific product, but you are not sure in which position of the association_chain it appears, then do this:
With the MongoDB shell you can access any hash key inside a nested structure with the '.' dot operator! Please note that this is independent of how deeply that key is nested in the record (isn't that cool?)
You can do a find on an embedded array of hashes like this:
db.items.find("association_chain.name":"something")
This returns all records in the collection which contain the desired product mentioned anywhere in the association_array.
If you want to do this, you should make sure that you have an index:
db.items.ensureIndex({"association_chain.name":1},{background: 1})
See "Dot Notation" on this page: http://docs.mongodb.org/manual/core/document/
You can do this with the aggregation framework. In the mongo shell run a query that unwinds the documents so you have a document per array element (with duplicated data in the other fields), then group by id and any other field you want to include, plus the array with the operator $first. Then just include the $match operator to filter by name or mongoid.
Here's the query to match by the first product name:
db.foo.aggregate([
{ $unwind:"$association_chain"
},
{
$group : {
"_id" : {
"_id" : "$_id",
"other" : "$other"
},
"association_chain" : {
$first : "$association_chain"
}
}
},
{ $match:{ "association_chain.name":"Product"}
}
])
Here's how to query for the first product by mongoid:
db.foo.aggregate([
{ $unwind:"$association_chain"
},
{
$group : {
"_id" : {
"_id" : "$_id",
"other" : "$other"
},
"association_chain" : {
$first : "$association_chain"
}
}
},
{ $match:{ "association_chain.id":ObjectId("4e1e2cdd9a86652647000007")}
}
])
Related
I have following data in cosmosDb
[
{
accountId : "12453"
tag : "abc"
},
{
accountId : "12453"
tag : "bcd"
},
{
accountId : "34567"
tag : "qwe"
},
{
accountId : "34567"
tag : "xcx"
}
]
And desired output is something like this
[
{
accountId : "123453"
tag : {
"abc",
"bcd"
},
{
accountId : "34567"
tag : {
"qwe",
"xcx"
}
]
I tried Join, array and group by in multiple ways but didn't work.
Below query gives similar output but rather than count I am looking for an array of tags
select c.accountId, count(c.tag) from c where c.accountId = "12453" group BY c.accountId
Also tried below query
select c.accountId, ARRAY(select c.tag from c IN f where f.accountId = "12453") as tags FROM f
This doesn't return any tag values and I get below output but I need distinct accountId and when I try DISTINCT on accountId, it gives an error.
[
{
accountId : "12,
tag : []
}
........
]
Can someone please help with correct query syntax
As M0 B said, this is not supported. Cosmos DB can't combine arrays across documents. You need to handle this on your client side.
I have elasticsearch set up for searching across a products catalog's variants. Basically where:
Product has_many variants
Variant belongs_to product
And the variant index json / mapping contains the product name.
I am trying to search variants, grouped by product id, bucket size of 1. I am able to do it and sort by min price, max price, etc.
This works:
POST /variants/_search?size=0
{
"aggs" : {
"min_price" : { "min" : { "field" : "price" } }
}
}
This is (sort of) what I need next:
POST /variants/_search?size=0
{
"aggs" : {
"product_name" : { "sort by product_name asc / desc" }
}
}
My last task is about sorting them alphabetically, but I dont seem to be able to sort by a keyword field (asc/desc) using an aggregator.
In ES 6.0, you could do this. Note that size limits how many are returned, and the more you request the more expensive the query will be to execute. So if you really need many thousands you will probably want to try a different approach. Probably something where you created a separate rolled up index for products that you could search/sort instead of trying to do it through aggregations.
GET /variants/_search
{
"size": 0,
"aggs" : {
"product_name" : {
"terms" : {
"field" : "product_name",
"size": 1000,
"order" : { "_key" : "asc" }
}
}
}
}
Reference:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-order
Suppose I have documents with structure:
{
name:"some_name",
salary:INT_VAL,
date:YYYY.dd.MMTHH:mm:sssZ,
num_of_months:INT_VAL
}
And now I want to make a query to elastic, that would select top 10 documents that sorted by criteria salary*num_of_months.
How can I do this?
And what if I want to sort by criteria with some logic inside, sth. like
if (num_of_months < 5)
then criteria = salary*100 ;
elseif criteria = salary*200;
endif
sort_by_criteria()
Doing a Sort with a script will enable you to perform calculations on the data and return it in the right order:
GET /myindex/mytype/_search?pretty
{
"sort" :{
"_script" : {
"type" : "number",
"lang": "expression",
"script" : "doc['num_of_months'].value < 5 ? doc['salary']*100 : doc['salary']*200",
"order":"desc"
}
},
"size": 10
}
Note the use of the ternary operator to do the If statement.
I am using json to create nodes in noe4j
I have written a small c++ prog to do so using curl and json
Now i have to create around 10000 nodes in neo4j with properties having name and value.
For that i am using props in json with the query as
{
"params" : {
"props" : {
[{name : "a", value : 1}, {name : "b", value : 2}......so on]
]
}
},
"query" : "CREATE (n:Router { props }) RETURN n"
}
the question is I just want to create that nodes with unique names. If a node is already present with the name as in json props I do not want to create it.
How to write a query for these types of request in neo4j
Change your query to the following:
{
"params" : {
"props" : {
[{name : "a", value : 1}, {name : "b", value : 2}......so on]
]
}
},
"query" : "FOREACH (router in {props} | MERGE (n:Router {name: router.name}) ON CREATE SET n = router)"
}
Basically it iterate the items in your list, check for name property if it exist and it case it save a new node
So I'm trying to create a tree using a really basic parameterised cypher command, but I'm getting this error whenever I try to create more than one item at a time:
If you create multiple elements, you can only create one of each.
{
"query" : "MATCH (p) WHERE p.id='Hello' CREATE (c {props}), p-[r:CHILD]->c",
"params" : {
"props" : [ {
"type": 44,
"title" : "TestNode"
},{
"type": 45,
"title" : "TestNode"
} ]
}
}
What am I doing wrong?
When you pass an array of maps in the CREATE statement, you cannot also create relationships in the same statement.
By providing Cypher an array of maps, it will create a node for each map. When you do this, you can’t create anything else in the same CREATE statement.
See it in the docs here.
All you need to do is add another CREATE statement:
{
"query" : "MATCH (p) WHERE p.id='Hello' CREATE (c {props}) CREATE UNIQUE p-[:CHILD]->c",
"params" : {
"props" : [ {
"type": 44,
"title" : "TestNode"
},{
"type": 45,
"title" : "TestNode"
} ]
}
}