Flatten a document in document db - database

I have a document in document db that has a property that is an array of an object. I would like to flatten it and get a single property in all the objects in terms of an array.
eg:
{
"name" : "blah",
"address" : [
{
"type" : "home",
"location" : "123 st"
},
{
"type" : "work",
"location" : "321 st"
}
]
}
-> What I want
[
{
"name" : "blah",
"locations" : [ "123 st", "321 st" ]
}
]

You could try to define and use User-defined function to extract locations info.
And then you could call this User-defined function from inside your query.

Related

Compare array within objects in an array of the same Mongo document

I have a Mongo database with multiple documents and they all contain 2 Items for in store and online locations. The difference will be that attributes within the items object may differ. I am trying to capture all documents that have differing attributes between the object items with the array.
I've tried using $expr and comparing the position of the elements such as "Items.0.Attributes" == "Items.1.Attributes" but had no luck.
{
"ID" : "123456789",
"Items" : [
{
"ItemDept" : "softLines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts"
},
"Attributes" : [ "blue","small","mens"],
"Season" : "Summer"
"Location":"online"
}
,
{
"ItemDept" : "softlines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts")
},
"Attributes" : [ "blue","small","women"],
"Season" : "Summer"
"Location":"stores"
}
]
}
If I understand what you want to find/output, here's one way you could do it.
db.collection.find({
"$expr": {
"$not": {
"$setEquals": [
{"$first": "$Items.Attributes"},
{"$last": "$Items.Attributes"}
]
}
}
})
Try it on mongoplayground.net.

How to group records based on array elements using MongoDB

I have a data collection which contains a set of records in the following format.
{
"_id" : 22,
"title" : "3D User Interfaces with Java 3D",
"isbn" : "1884777902",
"pageCount" : 520,
"publishedDate" : ISODate("2000-08-01T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/barrilleaux.jpg",
"longDescription" : "Description",
"status" : "PUBLISH",
"authors" : [
"Jon Barrilleaux"
],
"categories" : [
"Java",
"Computer Graphics"
]
},
{
"_id" : 23,
"title" : "Specification by Example",
"isbn" : "1617290084",
"pageCount" : 0,
"publishedDate" : ISODate("2011-06-03T07:00:00Z"),
"thumbnailUrl" : "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
"status" : "PUBLISH",
"authors" : [
"Gojko Adzic"
],
"categories" : [
"Software Engineering"
]
}
Please note that the 'categories' is an array.
I want to count the published books for each category. I tried the following solution, but it treated the entire array as one group.
db.books.aggregate([
{
$group:{_id:"$categories", total:{$sum:1}}
}
])
Instead of so, I want to count the number of records for each individual category value inside 'categories' array.
You should first use $unwind which outputs one document for each element in the array.
db.books.aggregate([
{
$unwind : "$categories"
},
{
$group : { _id : "$categories", total: { $sum: 1 } }
}
])

Query for deeply nested array in mongodb

How do I query a deeply nested docs like show in the below image.
Here columns is an array of unknown size. Each element in the column contains a record that is again an array. Each element of the record array contains an array called fields. Each entry in the field contains 2 keys called name and value.
I'm querying the name of the innermost array (in fields array). I couldn't go above level 1 order of nesting.
JSON doc of the above image
"data" : {
"columns" : [
{
"name" : "styleId",
"record" : [
{
"fname" : "column_mapping",
"_id" : ObjectId("5ba488c79dc6d62c90257752"),
"fields" : [
{
"name" : "column_mapping_form",
"value" : "styleId"
}
],
"rules" : [
[
]
]
}
]
},
{
"name" : "vendorArticleNumber",
"record" : [
{
"fname" : "column_mapping",
"_id" : ObjectId("5ba488c79dc6d62c90257753"),
"fields" : [
{
"name" : "column_mapping_form",
"value" : "vendorArticleNumber"
}
],
"rules" : [
[
]
]
}
]
},
{
"name" : "vendorArticleName",
"record" : [
{
"fname" : "column_mapping",
"_id" : ObjectId("5ba488c79dc6d62c90257754"),
"fields" : [
{
"name" : "column_mapping_form",
"value" : "vendorArticleName"
}
],
"rules" : [
[
]
]
}
]
}
}
What can be the solutions if such kind of heaving nesting is there?
db.collection.find("data.columns.record.fields.name" : "column_mapping_form")
will match all documents where there is at least one element of columns has at least one record with at least one field where name is "column_mapping_form".
https://docs.mongodb.com/manual/tutorial/query-array-of-documents/ has very good explanation, examples, and interactive shell to play with.

MongoDB object property $exists in nested array

I have a folowing object structure in my db collection:
{
"name" : "test",
"code" : "test",
"attributes" : [
{
"name" : "test1",
"code" : "code1"
},
{
"name" : "test2",
"code" : "code2",
"value" : true
},
{
"name" : "test3",
"code" : "code3",
"value" : ""
},
{
"name" : "test4",
"code" : "code4"
"value" : [
{
"code" : "code4.1",
"name" : "test4.1"
},
{
"name" : "test4.2"
}
]
}
]
}
So "value" property can be empty string, boolean, array or even not defined at all.
How can I make query to list objects that have non-empty attributes array and don't have "attributes.value" property defined inside at least one object inside array?
p.s. I tried following query:
db.collection.find({"attributes": {$exists: true, $ne: []}, "attributes.value": {$exists: false}})
but query result is empty.
The $elemMatch operator matches documents that contain an array field
with at least one element that matches all the specified query
criteria.
This query work for me:
db.getCollection('testeur').find({ "attributes": {
$exists: true,
$ne: [],
$elemMatch: { "value": {$exists: false } }
}
})

MongoDB aggregation: Replacing sub-document with a value out from it

Let's say I have a collection of documents in the following format:
{
// some fields
"name" : "some name",
"specs" : [
{
"key" : {
"en" : "English key name",
"xx" : "Other key name",
},
"value" : {
"en" : "English value",
"xx" : "Other value",
}
},
{
"key2" : {
"en" : "English key name2",
"xx" : "Other key name2",
},
"value2" : {
"en" : "English value2",
"xx" : "Other value2",
}
},
//and some more sub-documents
],
}
I'm trying to query it from the database to get it in the following format:
{
"name" : "some name",
"specs" : [
{
"key" : "English key name",
"value" : "English value",
},
{
"key2" : "English key name2",
"value2" : "English value2",
},
//and some more sub-documents
],
}
How can it be done, if it is possible at all?
Background
I'm making a software which must be available in multiple languages, and I think current document schema is most suitable for this (if you've got better ideas for the schema I'd like to see them).
To minimize amount of data queried from the database, I'm trying to select the data only in one language. And moreover I want to minimize nesting of structures in the code, so I'm searching a way to somehow select a value out from a sub-document and replace the sub-document.
I've tried a lot of ways writing such query. Here's the one, but it doesn't work as I expect it to:
db.software.aggregate({
$project : {
"name" : true,
"specs" : {
"key" : "$specs.key.en",
"value" : "$specs.value.en"
}
}
});
It transforms a key into an array of all "key.en" fields within specs field. May there be a way to reference a current array element inside "specs" instead of the whole specs array?

Resources