How to correct document validation fail in Mongodb? - mongodb

Ive created the following collection(the creation of which is successful)
db.createCollection("Company", { "validator": { "$jsonSchema": {
"bsonType":"object",
"required":["city_name","city","street_name","building_number","budget","Department"],
"properties":{ "city_name":{ "bsonType":"string",
"description":"name of city" },
"city":{ "bsonType":"string",
"description":"City" },
"street_name":{ "bsonType":"string",
"description" :"name of street" },
"building_number":{"bsonType":"int",
"description":"number of building", minimum: 0, maximum: 500},
"budget":{"bsonType":"double",
"description":"budget of company",minimum: 0 },
"Department":{ "bsonType":"object",
"required":["Department_name","floor_number","Employee"],
"properties":{ "Department_name":{"bsonType":"string",
"description": "name of department" },
"floor_number":{"bsonType":"int",
"description":"number of floor" },
}},
"Employee":{ "bsonType":"object",
"required":["first_name","last_name","DOB","Salary"],
"properties":{"first_name":{"bsonType":"string",
"description":"Employees first name"},
"last_name":{"bsonType":"string",
"description":"Employees last name"},
"DOB":{"bsonType":"date",
"description":"Date of birth of empployee"},
"Salary":{"bsonType":"double",
"description":"Salary of Employee",minimum: 0},
"Position":{"bsonType":"string",
"description":"Position of employee. Field is not required"}}}}}}});
Ive created a set of data to insert into this collection to test the validations
db.Company.insert(
{ "city_name":"Sydney",
"city":"Sydney",
"street_name":"Pitt Street",
"building_number":100,
"budget": 100000.0,
"Department":{"department_name":"Google",
"floor_number":4,
"Employee" :{"first_name" : "George",
"last_name": "Martin",
"DOB": new Date('Dec 26,1981'),
"Salary" : "70000",
"Position": "CEO"}}
});
However when i run this script i get an error
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
Sadly Mongodb isnt very specific in what causes such errors and ive gone through my syntax and declarations and could not pick up on any errors myself,when clearly there is!
Why am i recieving this error when running my code? Thankyou

Try this:
01) Schema:
db.createCollection(
"Company",
{
"validator": {
"$jsonSchema": {
"bsonType":"object",
"required":["city_name","city","street_name","building_number","budget","Department"],
"properties": {
"city_name":{ "bsonType" : "string", "description" : "name of city" },
"city":{ "bsonType" : "string", "description" : "City" },
"street_name":{ "bsonType" : "string","description" : "name of street" },
"building_number": { "bsonType" : "int", "description" : "number of building", minimum: 0, maximum: 500},
"budget": { "bsonType" : "double", "description" : "budget of company",minimum: 0 },
"Department": {
"bsonType":"object",
"required":["Department_name","floor_number","Employee"],
"properties": {
"Department_name":{"bsonType":"string", "description": "name of department" },
"floor_number":{"bsonType":"int", "description":"number of floor" },
"Employee":{
"bsonType":"object",
"required":["first_name","last_name","DOB","Salary"],
"properties":{
"first_name":{"bsonType":"string", "description":"Employees first name"},
"last_name":{"bsonType":"string", "description":"Employees last name"},
"DOB":{"bsonType":"date", "description":"Date of birth of empployee"},
"Salary":{"bsonType":"double", "description":"Salary of Employee",minimum: 0},
"Position":{"bsonType":"string", "description":"Position of employee. Field is not required"}
}
}
}
},
}
}
}
}
);
02) Insert:
db.Company.insert(
{
"city_name": "Sydney",
"city": "Sydney",
"street_name": "Pitt Street",
"building_number": NumberInt(100),
"budget": 100000.0,
"Department":{
"Department_name":"Google",
"floor_number": NumberInt(4),
"Employee" : {
"first_name" : "George",
"last_name": "Martin",
"DOB": new Date('Dec 26,1981'),
"Salary" : 70000.0,
"Position": "CEO"
}
},
});
I have to do a few changes:
'int' fields have to be NumberInt(number) in the insert command.
The scheme has been changed so that 'Employee' is within 'Department'.
Salary must be double.

"Salary" : "70000" is an int, but the schema ask for double: "Salary":{"bsonType":"double", "description":"Salary of Employee",minimum: 0},.
I would recommend that you use the alias "bsonType":"number" in your schema instead of int,double, long, decimal. Since javascript is not typed, it can be a real pain to keep track which is used in your code.
See doc: https://docs.mongodb.com/manual/reference/operator/query/type/#available-types

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)

Object to group id in MongoDB pipelines

I have a MongoDB aggregation pipeline that returns such an output:
[
{
"id": {
"isPaid": false,
"state": "approved",
"updatedAt": "2018-06-27"
},
"state": "approved",
"isPaid": false,
"updatedAt": "2018-06-27",
"totalCount": 1,
"totalValue": 658.4332
},
{
"id": {
"isPaid": false,
"state": "canceled",
"updatedAt": "2018-05-30"
},
"state": "canceled",
"isPaid": false,
"updatedAt": "2018-05-30",
"totalCount": 1,
"totalValue": 1735.7175
},
]
For the system that exploits it, I'd need id to be available, as a string.
So I'm wondering if, using an aggregation pipeline stage, there would be an elegant and generic way to concatenate/serialize object values to a string:
"id": {"isPaid": false, "state": "approved", "updatedAt": "2018-06-27"}
to something like:
"id": "0.approved.2018-06-27"
you can use $concat
db.t55.aggregate([
{$addFields : {
id : {$concat : [{$cond :["$isPaid", "1","0"]}, ".", "$state", "." ,"$updatedAt"]}
}}
])
using $toString if not just true/false
db.t55.aggregate([
{$addFields : {
id : {$concat : [{$toString :{$indexOfArray : [[false,true], "$isPaid"]}}, ".", "$state", "." ,"$updatedAt"]}
}}
])
output
{ "_id" : ObjectId("5c3e794b21526e3ff4bf4ca2"), "id" : "0.approved.2018-06-27", "state" : "approved", "isPaid" : false, "updatedAt" : "2018-06-27", "totalCount" : 1, "totalValue" : 658.4332 }
{ "_id" : ObjectId("5c3e794b21526e3ff4bf4ca3"), "id" : "0.canceled.2018-05-30", "state" : "canceled", "isPaid" : false, "updatedAt" : "2018-05-30", "totalCount" : 1, "totalValue" : 1735.7175 }

mongodb Can't get the query to work

I'm trying to do a query in mongodb but I can't get it to work.
My document looks something like this.
{
"_id" : ObjectId("5305e54133e65b7341d63af3"),
"clients" : [
{
"aggregations" : {
"department" : [
"department1",
"department3"
],
"customer" : "customer2"
},
"lastLogin" : ISODate("2014-02-26T09:41:56.445Z"),
"locale" : "en"
"name" : "Test",
"validFrom" : null,
"validTo" : null,
"visiting" : {
"phone" : "031-303030",
"company" : "MyCompany",
"office" : [
"jag är ett test",
"lite mer data"
],
"country" : "Norge"
}
},
{
"approvedEmailSent" : true,
"lastLogin" : ISODate("2014-03-01T15:27:12.252Z"),
"locale" : "en",
"name" : "Test2",
"visiting" : {
"phone" : "031-307450",
"company" : "Other Company",
"branch" : "Advertising agency"
}
}
],
"firstname" : "Greger",
"lastname" : "Aronsson",
"username" : "TheUsername"
}
As you can see a user can have many clients. They are matched by name. The clients have visiting.company but sometimes this will not be the case.
I want to query where the clients.name is Test and regexp for visting.company and also firstname, lastname. If I'm logged in at Test2 I don't want hits on visiting.company "MyCompany". Hope this makes sense!
You can write query like :
db.visitCompany2.find({ $or : [
{'clients.name': 'Test2'}, //Company name
{'clients.visiting.company': {
$regex: /Other/g //Your visiting company regex
}},
{firstname: "Greger"},
{"lastname": "Aronsson}"
]}, {
'clients.$': 1, //projection for clients
firstname: 1,
lastname: 1
});
Output:
{
"_id": ObjectId("5305e54133e65b7341d63af3"),
"clients": [{
"approvedEmailSent": true,
"lastLogin": ISODate("2014-03-01T15:27:12.252Z"),
"locale": "en",
"name": "Test2",
"visiting": {
"phone": "031-307450",
"company": "Other Company",
"branch": "Advertising agency"
}
}],
"firstname": "Greger",
"lastname": "Aronsson"
}