compare two collections in mongodb using java or an simple query - mongodb

I am having following document (Json) of an gallery,
{
"_id": "53698b6092x3875407fefe7c",
"status": "active",
"colors": [
"red",
"green"
],
"paintings": [
{
"name": "MonaLisa",
"by": "LeonardodaVinci"
},
{
"name": "JungleArc",
"by": "RayBurggraf"
}
]
}
Now I am also having one collection of colors say
COLORS-COLLECTION: ["black","yellow","red","green","blue","pink"]
I want to fetch paintings by it's name matching to provided text say "MonaLisa" (as search query) also I want to compare two colors with COLORS-COLLECTION, if colors has any of the matching color in COLORS-COLLECTION then it should return the painting.
I want something like below:
{
"paintings": [
{
"name": "MonaLisa",
"by": "LeonardodaVinci"
}
]
}
Please help me!!. Thanks in advance.

If I get you correctly, aggregation framework would do your job:
db.gallery.aggregate([
{"$unwind": "$paintings"},
{"$match": {"paintings.name": 'MonaLisa', "colors": {"$in": ["black","yellow","red","green","blue","pink"]}}},
{"$project": {"paintings": 1, "_id": 0}}
]);

Related

Get specific fields from mongodb and return as object array

I have the following document:
"content": [
{
"_id": "5dbef12ae3976a2775851bfb",
"name": "Item AAA",
"itemImages": [
{
"_id": "5dbef12ae3976a2775851bfd",
"imagePath": "https://via.placeholder.com/300",
"imageTitle": "Test 300"
},
{
"_id": "5dbef12ae3976a2775851bfc",
"imagePath": "https://via.placeholder.com/250",
"imageTitle": "Test 250"
}
]
}
and I am wondering if there is a way to return only the data in the array yet with the "name" and document "main _id" so that result set will be
"itemImages": [
{
"_id": "5dbef12ae3976a2775851bfb",
"name": "Item AAA",
"imagePath": "https://via.placeholder.com/300",
"imageTitle": "Test 300"
},
{
"_id": "5dbef12ae3976a2775851bfb",
"name": "Item AAA",
"imagePath": "https://via.placeholder.com/250",
"imageTitle": "Test 250"
}
]
I've tried using mongodb find and aggregate functions but neither helped in retrieving the above results. Thanks for your help
You should be able to get what you want with aggregation.
You'll need to:
unwind the array so there is a separate document for each element
use addFields to add the _id and name to the element
group to reassemble the array
project to get just the field you want
This might look something like:
db.collection.aggregate([
{$unwind:"$itemImages"},
{$addFields: {
"itemImages._id":"$_id",
"itemImages.name":"$name"
}},
{$group:{_id:"$_id", itemImages:{$push:"$itemImages"}}},
{$project:{itemImages:1,_id:0}}
])

MongoDB, remove nested doc in an array

I have the following structure in MongoDB and I try to remove the documents that contains specific tags. I can't seem to be able to get the $pull work.
In this example, I would like to pull the nested doc that has has tags :["BB"]
Any help will be appreciated !
{
"_id": 123,
"socialItems": {
"facebook": [{
"name": "firstFacebook",
"id": 2
}, {
"name": "secondFB",
"id": 43
}],
"instagram": [{
"name": "firstNstagram",
"id": 4
}],
"pc": [{
"name": "firstPC",
"id": 55,
"tags": [
"ab"
]
}, {
"name": "secondPC",
"id": 66,
"tags": [
"BB"
]
}]
}
}
I assume you are trying to drop the nested 'pc' doc, from the array? You also don't mention if you're using a specific driver for this, so I've assumed you're running this in the Mongo shell.
The following will remove documents from the 'pc' property, when containing the 'BB' tag.
db.collectionName.update({'socialItems.pc.tags': 'BB'}, {$pull: {'socialItems.pc': {tags: 'BB'}}})

Find specific mongoldb document from nested array

This is my document in MongoDB:
{
"_id": {
"$oid": "566193b0c9b5290f234242"
},
"name": "fake-name-1",
"profiles": [
{
"real-name": "fake-name-1",
"color": "fake-color-1"
},
{
"real-name": "fake-name-2",
"color": "fake-color-2",
"active": true
},
{
"real-name": "fake-name-3",
"color": "fake-color-3"
}
]
}
I'm real newbie to MondoDb, and are trying to find the document where profiles contains a real-name with "MArtin43221" and active = true.
How do I create a search query for this?
I've tried:
{"profiles": ["real-name":"MArtin43221", "active":true]}
Try elemMatch:
db.collection.find({"profiles": {$elemMatch:{"real-name":"MArtin43221", "active":true}}})

Elasticsearch date range aggregation over multiple fields

My documents' structure look like this:
{
"element": "A",
"date": "2014-01-01",
"valid_until": "2014-02-01"
},
{
"element": "A",
"date": "2014-02-01",
"valid_until": "9999-12-31"
}
The date "9999-12-31" is here to say: "it has not yet expired". There is always range like this, so for a given element "A", date > valid_until can never overlaps. I can therefore count how much element I have by using the pseudo-code like this: COUNT elements WHERE date < date_to_count AND valid_until >= date_to_count
Where "date_to_count" is the date at which I want to count the values for. As I want to calculate this at several points in time, I could either use a date histogram, or a date range aggregation. However, the date range does seem to work only with one kind of field. Ideally, I'd like to be able to do that:
"aggs": {
"foo": {
"date_range": {
"fields": ["date", "valid_until"],
"ranges": [
{"from": "2014-01-01", "to": {"2014-02-01"}},
{"from": "2014-02-01", "to": {"2014-03-01"}},
{"from": "2014-03-01", "to": {"2014-04-01"}}
]
}
}
}
Where the "date" will be used for "from", and the "valid_until" would be used for "to".
I've tried several other ideas with script, but can't find an efficient way to do it this way :/.
I think I could also workaround this if, in a script, I could have access to the current from/to values, but once again, I've tried things like "ctx.to", "context.to", but those variables are undefined.
Thanks!
Since both the date_range and date_histogram aggregations work on a single field, I do not think you can achieve your goal with an aggregation. But if you don't have too many date ranges that you need to query for, you could call the count API with a query for each date range. That would look something like this:
"query": {
"filtered": {
"filter": {
"bool" {
"must": [
{ "range": { "date": { "gte": "2014-01-01" }}},
{ "range": { "valid_until": { "lt": "2014-02-01" }}}
]
}
}
}
}
I was facing the same problem, and wanted to address this by using one single query. Here is the solution that works for me in Elasticsearch 5.2
"aggs": {
"range1": {
"date_range": {
"fields": "date",
"ranges": [
{"from": "2014-01-01", "to": {"2014-02-01"}},
{"from": "2014-02-01", "to": {"2014-03-01"}},
{"from": "2014-03-01", "to": {"2014-04-01"}}
]
},
"range2": {
"date_range": {
"field": "valid_until",
"ranges": [
{"from": "2014-01-01", "to": {"2014-02-01"}},
{"from": "2014-02-01", "to": {"2014-03-01"}},
{"from": "2014-03-01", "to": {"2014-04-01"}}
]
}
}
}

removing an entire subdocument mongodb

This should be really easy but I cant seem to get it working;
I just need to remove a sub-document that I had accidentally run and introduced undesirable info in the sub-document.
I tried - db.test.remove({}, {dcoll10:{"$exists": true}, {multi: true}); but this didnt work.
Example of document and sub-doc (dcoll10) is given below;
{
"_id": "SSS",
"ts": { "$date": 1395927614611 },
"dcoll10": [
{
"_id": "SSS",
"type": "1813",
"gro": "0.1",
},
{
"_id": "SSS",
"type": "1813",
"gro": "0.1",
}
],
"assima" : [
{......}
]
}
It sounds like you want the $unset operator which is documented here: http://docs.mongodb.org/manual/reference/operator/update/unset/