How to change the response in MongoDB using translatable fields - mongodb

I am looking for the way how to resolve this and I can't find it. I appreciate your help.
I have a collection with products like:
[
{
"name": [
{ "es": "Producto 1" },
{ "en": "Product 1" }
]
"reference": "PR1",
"price": "20",
"description": [
{ "es": "Descripción 1" },
{ "en": "Description 1" }
]
}
]
And I would like to do:
db.products.aggregate(); // Find by language es for example:
And get:
[
{
"name": "Producto 1",
"reference": "PR1",
"price": "20",
"description": "Descripción 1"
}
]
Thanks very much.

I would suggest a schema change though to this:
[
{
"name" : [
{
"language" : "es",
"description" : "Producto 1"
},
{
"language" : "en",
"description" : "Product 1"
}
],
"reference" : "PR1",
"price" : "20",
"description" : [
{
"language" : "es",
"description" : "Descripción 1"
},
{
"language" : "en",
"description" : "Description 1"
}
]
}
]
cause then you could actually group by the language in your case.
If this is possible then you could do the following:
db.products.aggregate([
{$unwind: "$someName"},
{$unwind: "$someName.name"},
{$unwind: "$someName.description"},
{
$group: {
_id: {namelang: "$someName.name.language", namedesc: "$someName.description.language"},
name: {$first: "$someName.name.description"},
reference: {$first: "$someName.reference"},
price: {$first: "$someName.price"},
description: {$first: "$someName.description.description"}
}
},
{
$match: {
"_id.namelang": "en",
"_id.namedesc": "en"
}
}
])
FYI since you didn't provided your complete json I created one random. Here is the complete schema:
{
"_id" : ObjectId("59ea07a600f5db2660dbf162"),
"someName" : [
{
"name" : [
{
"language" : "es",
"description" : "Producto 1"
},
{
"language" : "en",
"description" : "Product 1"
}
],
"reference" : "PR1",
"price" : "20",
"description" : [
{
"language" : "es",
"description" : "Descripción 1"
},
{
"language" : "en",
"description" : "Description 1"
}
]
}
]
}

Related

How can we rename a field or give alias to field in MongoDB Atlas charts?

How can we rename a field or give alias to field in MongoDB Atlas charts?
Examples:
this is the students collection
{
"_id": 1,
"alias": [ "The American Cincinnatus", "The American Fabius" ],
"mobile": "555-555-5555",
"nmae": { "first" : "george", "last" : "washington" }
},
{
"_id": 2,
"alias": [ "My dearest friend" ],
"mobile": "222-222-2222",
"nmae": { "first" : "abigail", "last" : "adams" }
}
Here I update the nmae field to name
db.students.updateMany( {}, { $rename: { "nmae": "name" } } )
{
"_id": 1,
"alias": [ "The American Cincinnatus", "The American Fabius" ],
"mobile": "555-555-5555",
"name": { "first" : "george", "last" : "washington" }
},
{
"_id" : 2,
"alias" : [ "My dearest friend" ],
"mobile" : "222-222-2222",
"name" : { "first" : "abigail", "last" : "adams" }
}
ref: https://docs.mongodb.com/manual/reference/operator/update/rename/

Getting an array out of the input using aggregate

My input file looks like this:
[
{
"type" : "asdf",
"properties" : {
"Name" : "First center",
"Code" : "ABCD",
"Address" : "Emmastr 14",
"City" : "Rotterdam",
"Postcode" : 55968,
}
},
{
"type" : "qwer",
"properties" : {
"Name" : "Second center",
"Code" : "OTHER",
"Address" : "Havenstraat 15",
"City" : "Rotterdam",
"Postcode" : 88767,
}
},
{
"type" : "zxcv",
"properties" : {
"Name" : "Third center",
"Code" : "ABCD",
"Address" : "Kerkstraat 16",
"City" : "Amsterdam",
"Postcode" : 33948,
}
},
{
"type" : "tyiu",
"properties" : {
"Name" : "Fourth center",
"Code" : "ABCD",
"Address" : "Zeestraat 17",
"City" : "Amsterdam",
"Postcode" : 56475,
}
}
]
I've been tasked to present this information grouped per city (a document for each city).
Only the items that have Code="ABCD" should appear in the output.
Output should be ordered by city name (_id).
Output should be written to a new collection.
So the output I'm looking for is something like this:
_id: "Amsterdam",
center: [
{"Name": "Third center" , "Postcode": 33948, "Address": "Kerkstraat 16"},
{"Name": "Fourth center" , "Postcode": 56475, "Address": "Zeestraat 17"}
]
_id: "Rotterdam",
center: [
{"Name": "First center" , "Postcode": 55968, "Address": "Emmastr 14"}
]
This little snippet filter by "ABCD", groups by city and writes the output to a new collection.
db.centers.aggregate ([
{$match: {"properties.Code": "ABCD"}}
,{ $group: {_id: "$properties.City"}}
,{ $out: "newColl"}
])
But I'm not getting much further because of lack of hands on experience.
I struggle getting an array out of something that's not an array in the input. Is there anyone that could help?
$push to make array of required fields
$sort by _id in ascending order
db.centers.aggregate([
{ $match: { "properties.Code": "ABCD" } },
{
$group: {
_id: "$properties.City",
center: {
$push: {
Name: "$properties.Name",
Postcode: "$properties.Postcode",
Address: "$properties.Address"
}
}
}
},
{ $sort: { _id: 1 } },
{ $out: "newColl" }
])
Playground

MongoDB Return Inner Document From Array

I am trying to fetch an element from an array in a document and only the element I don't want the entire document
I tried a different method but they all return the entire document
db.dept.find({"section.classes.CRN":"1901"}).limit(100)
db.dept.where("section.classes.CRN").eq("1901").limit(100)
json
{
"_id" : ObjectId("5d70ab0c280d6b8ebb850cc1"),
"name" : "Art Studio",
"abbr" : "ARS",
"section" : [
{
"type" : "Undergraduate Courses",
"classes" : [
{
"CRN" : "193",
"Course" : "ARS100",
"Sec" : "01",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
"Days" : "MR",
"Time" : "1230P-0320P",
"Loc" : "SAB 226",
"Instructor" : "Schuck",
"Attributes" : "",
"Avail" : "F"
},
{
"CRN" : "293",
"Course" : "ARS100",
"Sec" : "02",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
"Days" : "MR",
"Time" : "0330P-0620P",
"Loc" : "SAB 226",
"Instructor" : "Itty",
"Attributes" : "",
"Avail" : "F"
},
{...
I am trying to get this or something similar when searching for a set of CRN values
json
[ {
"CRN" : "193",
"Course" : "ARS100",
"Sec" : "01",
"Title" : "Drawing I",
"Cr" : "3",
"Dates" : "8/26-12/19",
...
"Instructor" : "Schuck",
"Attributes" : "",
"Avail" : "F"
}
]
Try using the aggregate pipeline to project double nested array as:
Input:
[
{
"_id": ObjectId("5d70ab0c280d6b8ebb850cc1"),
"name": "Art Studio",
"abbr": "ARS",
"section": [
{
"type": "Undergraduate Courses",
"classes": [
{
"CRN": "193",
"Course": "ARS100",
"Sec": "01",
"Title": "Drawing I",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Time": "1230P-0320P",
"Loc": "SAB 226",
"Instructor": "Schuck",
"Attributes": "",
"Avail": "F"
},
{
"CRN": "293",
"Course": "ARS100",
"Sec": "02",
"Title": "Drawing I",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Time": "0330P-0620P",
"Loc": "SAB 226",
"Instructor": "Itty",
"Attributes": "",
"Avail": "F"
}
]
}
]
}
]
Query:
hereafter unwinding section you can filter classes for CRN
db.collection.aggregate([
{
$unwind: "$section"
},
{
$project: {
name: 1,
abbr: 1,
"section.type": 1,
"section.classes": {
$filter: {
input: "$section.classes",
as: "item",
cond: {
$eq: [
"$$item.CRN",
"193"
]
}
}
}
}
},
{
$group: {
_id: "$_id",
section: {
$push: "$section"
}
}
}
])
Output:
you can manage your keys as you want in project for adding new keys or replacing them.
[
{
"_id": ObjectId("5d70ab0c280d6b8ebb850cc1"),
"section": [
{
"classes": [
{
"Attributes": "",
"Avail": "F",
"CRN": "193",
"Course": "ARS100",
"Cr": "3",
"Dates": "8/26-12/19",
"Days": "MR",
"Instructor": "Schuck",
"Loc": "SAB 226",
"Sec": "01",
"Time": "1230P-0320P",
"Title": "Drawing I"
}
],
"type": "Undergraduate Courses"
}
]
}
]
db.dept.find({"section.classes.CRN":"1901"},{"section.classes":1}).limit(100)
It's called projection in mongodb, you pass a second object in find query to specify which fields you want in result.
so according to your above case if you want name, and section in result you should pass something like this
db.dept.find({"section.classes.CRN":"1901"},{"name":1, "section":1}).limit(100)

mongodb aggregation with array

I have data like this:
{
"_id" : ObjectId("..."),
"name" : "Entry 1",
"time" : ISODate("2013-12-28T06:00:00.000Z"),
"value" : 100
},
{
"_id" : ObjectId("..."),
"name" : "Entry 2",
"time" : ISODate("2013-12-28T06:00:00.000Z"),
"value" : 200
},
{
"_id" : ObjectId("..."),
"name" : "Entry 1",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 110
},
{
"_id" : ObjectId("..."),
"name" : "Entry 2",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 230
},
{
"_id" : ObjectId("..."),
"name" : "Entry 3",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 25
},
{
"_id" : ObjectId("..."),
"name" : "Entry 4",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 15
}
I need the result grouped by time with percentage for each entry like this (group entries by volume "others" when entries for time period more than two, but it's not necessary):
{
"_id": ISODate("2013-12-28T11:00:00.000Z"),
"entries": [
{
"name": "Entry 1",
"percentage": 33.3
},
{
"name": "Entry 2",
"percentage": 66.6
},
]
},
{
"_id": ISODate("2013-12-28T06:00:00.000Z"),
"entries": [
{
"name": "Entry 1",
"percentage": 28.9
},
{
"name": "Entry 2",
"percentage": 60.5
},
{
"name": "Others",
"percentage": 10.5
}
]
}
So the request I was try:
db.collection.aggregate([
{
"$addFields": {
"full_datetime": {"$substr": ["$time", 0, 19]}
}
},
{
"$group": {
"_id": "$full_datetime",
"value_sum": {"$sum": "$value"},
"entries": {
"$push": {
"name": "$name",
"percentage": {
"$multiply": [{
"$divide": ["$value", {"$literal": "$value_sum" }]
}, 100 ]
}
}
}
}
}
])
This request is not work because $value_sum does not exists inside $push.
Please help me how I can to send this $value_sum into the $push statement
You can use one more stage to calculate percentage using $map as,
db.collection.aggregate([
"$addFields": {
"full_datetime": {
"$substr": ["$time", 0, 19]
}
}
}, {
"$group": {
"_id": "$full_datetime",
"value_sum": {
"$sum": "$value"
},
"entries": {
"$push": {
"name": "$name",
"value": "$value"
}
}
}
}, {
"$project": {
"entriesNew": {
"$map": {
"input": "$entries",
"as": "entry",
"in": {
"name": "$$entry.name",
"percentage": {
"$multiply": [{
"$divide": ["$$entry.value", "$value_sum"]
}, 100]
}
}
}
}
}
}])
Output:
/* 1 */
{
"_id" : "2013-12-28T11:00:00",
"entries" : [
{
"name" : "Entry 1",
"percentage" : 28.9473684210526
},
{
"name" : "Entry 2",
"percentage" : 60.5263157894737
},
{
"name" : "Entry 3",
"percentage" : 6.57894736842105
},
{
"name" : "Entry 4",
"percentage" : 3.94736842105263
}
]
}
/* 2 */
{
"_id" : "2013-12-28T06:00:00",
"entries" : [
{
"name" : "Entry 1",
"percentage" : 33.3333333333333
},
{
"name" : "Entry 2",
"percentage" : 66.6666666666667
}
]
}

mongodb find element in array or less but no other

I have this collection:
{
"title": "First Item",
"attributes": [
{
"id": "1",
"text": "Alpha"
},
{
"id": "2",
"text": "Bravo"
},
{
"id": "3",
"text": "Charlie"
}
]
},
{
"title": "Second Item",
"attributes": [
{
"id": "1",
"text": "Alpha"
},
{
"id": "2",
"text": "Bravo"
},
{
"id": "3",
"text": "Tango"
}
]
}
Trying search with these values for "attributes.text" field:
{ "Alpha", "Bravo", "Charlie", "Delta" }
I want to find only "First Item" document that contains at least these keys but no others.
But trying these values:
{ "Alpha", "Bravo", "Delta" }
or
{ "Alpha", "Bravo" }
I do not want to find any result (beacuse "Charlie" is missing).
Thank you
Use the $in operator to match values in the attributes object array. The following query will select all documents in the collection where the text field value of the attribute object array is either "Alpha", "Bravo" or "Delta":
dbo.collection.find({
"attributes.text": {
"$in": ["Alpha", "Bravo", "Delta"]
}
});
This will return the two documents:
/* 0 */
{
"_id" : ObjectId("551187bae3757367bf8bd915"),
"title" : "First Item",
"attributes" : [
{
"id" : "1",
"text" : "Alpha"
},
{
"id" : "2",
"text" : "Bravo"
},
{
"id" : "3",
"text" : "Charlie"
}
]
}
/* 1 */
{
"_id" : ObjectId("551187bae3757367bf8bd916"),
"title" : "Second Item",
"attributes" : [
{
"id" : "1",
"text" : "Alpha"
},
{
"id" : "2",
"text" : "Bravo"
},
{
"id" : "3",
"text" : "Tango"
}
]
}