I have simple mapping - one string field and one string[] field.
The array of strings contains duplicate values, and I get those duplicate values in query:
{ "query" : { "term" : {"id" : "579a252585b8c5c428fa0a3c"} } }
Returns a single valid hit:
{
"id" : "579a252585b8c5c428fa0a3c",
"touches" : [ "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b457b", "5639abfb5cba47087e8b457b"
}
But in metric script aggregation:
"aggs": {
"path": {
"scripted_metric": {
"map_script": "_agg['result'] = doc['touches'].values"
}
}
}
retuns
"aggregations" : {
"path" : {
"value" : [ { }, {
"result" : [ "5639abfb5cba47087e8b4571", "5639abfb5cba47087e8b457b" ]
}, { }, { }, { } ]
}
}
that element is org.elasticsearch.index.fielddata.ScriptDocValues$Strings, casting it toString() returns a json-encoded 2-element array.
So, the question:
Why does ScriptDocValues$Strings return only unique array values and how to get the initial array in script aggregation?
Thanks.
UPD
I found that for numerical values (in particular floats) everything works perfect.
Related
I have a database of products in MongoDB. Inside main objects, there is another object "GL_related", and inside the "GL_related" object there is an array "also_viewed". How can I count the elements inside the "also_viewed" array of a specific object with the title "Sunglasses"(by using the aggregate pipeline method)?
The result should be "4".
Sample data:
/* 1 */
{
"_id" : ObjectId("5d0b6d1cd7367de7f58b4908"),
"GL_asin" : "0456840532",
"GL_title" : "Sunglasses",
"GL_related" : {
"also_viewed" : [
"B001K9DPPC",
"B00BV9MU2K",
"B0042FHTDK",
"B003KK5LEW"
]
}
}
/* 2 */
{
"_id" : ObjectId("5d0b6d1cd7367de7f58b4907"),
"GL_asin" : "0456856293",
"GL_title" : "T-Shirt",
"GL_related" : {
"also_viewed" : [
"B005P1HF2U",
"B006K5JWOE"
]
}
}
You can just use Mongo's dot notation combined with $size
db.collection.aggregate([
{
"$project": {
itemCount: {
$size: "$GL_related.also_viewed"
}
}
}
])
Mongo Playground
I'm trying to do something which should be pretty straightforward. The aggregrate pipeline allows you to pass documents through stages in sequence. For example, I can filter out some documents and pass the documents I want to the next stage. This can be accomplished with $match. Then I want to take the remaining documents and group them by a field to check for duplicates. But I am having major issues with this. This is what I have tried:
db.my_fields.aggregate(
{ '$match' : { related_code_id: { "$in" : [ BSON::ObjectId('5cddd0143ed1495e5c000008'),BSON::ObjectId('5cddd0143ed1495e5c000010')] } } },
{ '$group' : { _id: { 'field' : '$field', 'field_type_id' : '$field_type_id' }, count: { '$sum' : 1} } },
{'$match' : { count: {'$gt' : 1} } }
)
The query works fine except for the first $match. Inside the $in statement, I am getting this error:
2019-05-17T18:47:56.602-0400 E QUERY [js] SyntaxError: missing ] after element list #(shell):2:95
It is complaining about this part right here:
BSON::ObjectId('5cddd0143ed1495e5c000008'),BSON::ObjectId('5cddd0143ed1495e5c000010')
How can I resolve this issue and achieve my goal of getting this basic query working?
Converting the ObjectId to BSON isn't needed:
https://docs.mongodb.com/manual/reference/method/db.collection.find/#query-using-operators
// ...
'$match': {
related_code_id: {
"$in": [
ObjectId('5cddd0143ed1495e5c000008'),
ObjectId('5cddd0143ed1495e5c000010')
]
}
}
// ...
If you are using Mongoose as ORM, you can solve it as follows.
db.my_fields.aggregate(
{ '$match' : { related_code_id: { "$in" : [ mongoose.Types.ObjectId('5cddd0143ed1495e5c000008'),mongoose.Types.ObjectId('5cddd0143ed14 95e5c000010')] } } },
{ '$group' : { _id: { 'field' : '$field', 'field_type_id' : '$field_type_id' }, count:
{ '$sum' : 1} } },
{'$match' : { count: {'$gt' : 1} } }
)
I have the following document:
{
"_id":"575322d9585095d9929554ba",
"Level1":{
"Level2":[
{
"Level3a":{
"Level4":{
"Level5":{
"name":"John",
"surname":"Matthew"
}
}
}
},
{
"Level3a":{
"Level4":{
"Level5":{
"name":"Emma",
"surname":"Jackson"
}
}
}
}
]
}
}
I need to insert the new name and surname at Level5. I tried the $push method but I got the error that the dotted field .. is not valid for storage:
db.names.update({ "_id":"575322d9585095d9929554ba" },
{
$push: {
"Level1.Level2":
{ $each: [ { "Level3a.Level4.Level5.name": "Greg" },
{ "Level3a.Level4.Level5.surname": "Cook" }] } } } )
It seems that push does not allow the inserting new data in hierarchical arrays or I am wrong?
There is an issue with your query as $each is used to add multiple values to same array....
As we are going to add only one entry to array we don't need to use $each
so query looks like this:
db.vnenad.update({
"_id" : "575322d9585095d9929554ba"
},
{
$push : {
"Level1.Level2" : {
"Level3a" : {
"Level4" : {
"Level5" : {
"name" : "johnny",
"surname" : "rambo"
}
}
}
}
}
})
as I was debbuging your query I decided to create variable with document to insert inside an array, then it was easier for me to adjust your query - please see below:
var doc = {
"Level3a" : {
"Level4" : {
"Level5" : {
"name" : "johnny",
"surname" : "rambo"
}
}
}
}
db.vnenad.update({
"_id" : "575322d9585095d9929554ba"
},
{
$push : {
"Level1.Level2" : doc
}
})
I'm trying to update an array within a document and it works correctly, but when I want to add a new element with upsert fails how to run an error. I've been searching on google for a few hours and the mongodb documentation and what I have tried I cannot operate.
The structure of the collection is:
{
"name" : String,
"providerId": Number,
"description": String,
"providers": [
{
"merchantId": String,
"name": String,
"valid": Boolean,
"data": String
},
{
"merchantId": String,
"name": String,
"valid": Boolean,
"data": String
},
{
"merchantId": String,
"name": String,
"valid": Boolean,
"data": String
}
]
}
Use this query to update existing data:
db.collection.update( { "providerId": ID, "providers": { $elemMatch: { "merchantId": MERCHANTID }}}, { $set: {
"providers.$.merchantId": MERCHANTID,
"providers.$.name": NAME,
"providers.$.valid": true,
"providers.$.data": DATA
}});
This working properly and correctly updated me the elements of the array. I want to when an element does not exist add it, without knowing if there are items or not, but not is if possible, probe to add upsert ( { upsert: true } ) parameter but gives me the following error. I think it is because it does not return any object search.
This is the error:
MongoError: The positional operator did not find the match needed from the query. Unexpanded update: providers.$.name
Is there any way to update the data in the subdocuments in the array and is compatible with add new ones if they don't exist? I've tried to search with the operator $in and it gives me error; also probe to search in different ways ( { "providers.merchantId": MERCHANTID } ) and others.
Thanks
There is an option to achieve what you want.
// step 1
var writeResult = db.collection.update({
"providerId" : ID,
"providers" : {
$elemMatch : {
"merchantId" : MERCHANTID
}
}
}, {
$set : {
"providers.$.merchantId" : MERCHANTID,
"providers.$.name" : NAME,
"providers.$.valid" : true,
"providers.$.data" : DATA
}
});
// step 2
if (!writeResult.nModified) { // if step 1 has succeeded on update, nModified == 1, else nModified == 0
db.collection.update({
"providerId" : ID,
"providers.merchantId" : {
$ne : MERCHANTID // this criteria is necessary to avoid concurrent issue
}
}, {
"$push" : {
"prividers" : {
"merchantId" : MERCHANTID,
"name" : NAME,
"valid" : true,
"data" : DATA
}
}
});
}
I have a document in MongoDB as below.
{
"CorePrice" : 1,
"_id" : 166,
"partno" : 76,
"parttype" : "qpnm",
"shipping" :
[
{
"shippingMethod1" : "ground",
"cost1" : "10"
},
{
"shippingMethod2" : "air",
"cost2" : "11"
},
{
"shippingMethod3" : "USPS",
"cost3" : "3"
},
{
"shippingMethod4" : "USPS",
"cost4" : 45
}
]
}
My goal is to add CorePrice (1) to cost4 (45) and retrieve the computed value as a new column "dpv". I tried using the below query. However I receive an error exception: $add only supports numeric or date types, not Array. I'm not sure why. Any kind of help will be greatly appreciated.
db.Parts.aggregate([
{
$project: {
partno: 1,
parttype: 1,
dpv: {$add: ["$CorePrice","$shipping.cost1"]}
}
},
{
$match: {"_id":{$lt:5}}
}
]);
When you refer to the field shipping.cost1 and shipping is an array, MongoDB does not know which entry of the shipping-array you are referring to. In your case there is only one entry in the array with a field cost1, but this can't be guaranteed. That's why you get an error.
When you are able to change your database schema, I would recommend you to turn shipping into an object with a field for each shipping-type. This would allow you to address these better. When this is impossible or would break some other use-case, you could try to access the array entry by numeric index (shipping.0.cost1).
Another thing you could try is to use the $sum-operator to create the sum of all shipping.cost1 fields. When there is only one element in the array with a field cost1, the result will be its value.
I am able to achieve this by divorcing the query into two as below.
var pipeline1 = [
{
"$unwind": "$shipping"
},
{
$project:{
partno:1,
parttype:1,
dpv:{
$add:["$CorePrice","$shipping.cost4"]
}
}
},
{
$match:{"_id":5}
}
];
R = db.tb.aggregate( pipeline );