Problems with JSON - arrays

I'm trying to Order in ascending order the requirements that are not between 25,000 and 30,000. The requirements are information of an array which is inside of a document and the condition is that they can't be in that determined range. I'm trying to do it properly but i can't find any information about this.
Document structure
{
"_id" : ObjectId("5ec73abebd7e4d618a05734e"),
"code" : "A47",
"title" : "Software engineer",
"description" : "Analyze, design, create, test computer and software systems.",
"city" : "Madrid",
"date" : ISODate("2020-05-22T02:36:46.271Z"),
"salary" : 30000.0,
"active" : true,
"requirements" : [
"python",
"java",
"html5",
"C++",
"C#"
],
"info_company" : {
"cif" : "A00000000",
"name" : "FUTURE S.A",
"location" : "Madrid",
"web" : "www.future.es",
"about" : "We are a leading company in new technologies."
},
"pyme" : true
}
db.offers.update(
{ $ne : [ salary: {
$gte : 25000,
$lte : 35000 ]
} },
{
$push : {
requirements: {
$each : [] ,
$sort : 1
}
}
}
,
{
multi : true
} )

Related

Remove objects within array in MongoDB

I need to remove all the objects within array who meet the conditions i will show down below. I'll let here the documents and an example of what i've done.
//document 1
{
"_id" : ObjectId("5ec73abebd7e4d618a057350"),
"code" : "X20",
"title" : "Full stack developer",
"location" : "Paris",
"date" : ISODate("2020-05-22T02:36:46.272Z"),
"candidates" : [
{
"name" : "David",
"last_name" : "Broncano",
"telephone" : "642025552",
"email" : "david#gmail.com"
},
{
"name" : "Pablo",
"last_name" : "Claros",
"telephone" : "628721784",
"email" : "pablo#gmail.com"
}
]
}
// document 2
{
"_id" : ObjectId("4ec73abebd7e4d618a057350"),
"code" : "X50",
"title" : "Full stack developer",
"location" : "Madrid",
"date" : ISODate("2020-05-22T02:36:46.272Z"),
"candidates" : [
{
"name" : "Maria",
"last_name" : "Mars",
"telephone" : "642024582",
"email" : "dasd#gmail.com"
},
{
"name" : "Pablo",
"last_name" : "Claros",
"telephone" : "628721784",
"email" : "pablo#gmail.com"
}
]
}
So i need to remove all the candidates where location is Madrid.I have done this but it removes the field. Is it possible to just remove the content of it using $pull or something?
db.offers.update(
{ location : "Madrid"},
{
$unset:{
"candidates":""
} } ,
{
multi : true
}
)
According to my understanding, you need to just clear the candidates array and maintain that as candidates: []. For this, you can use use $set operator to set candidates to [] based on your condition
db.offers.update({ location : "Madrid"}, { $set:{ "candidates": [] } } , { multi : true })

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 } }
}
])

Aggregate from one document array to another

I am trying to do a transformation from one data structure to another and am using NoSQL Booster as I feel more comfortable using SQL queries than I do using Mongo script, a little lazy but its worked for me thus far.
I have a document which has a an array of line items which represents a sales receipt. The line items are the items sold.
I have used the following SQL query to generate Mongo script to select and then rename values from one document to create another. Where I'm stuck is in selecting from an array some fields and renaming them into a new document within a new array.
mb.runSQLQuery(`
SELECT object_origin,
party_uuid AS company,
connection_uuid AS connection,
object_created AS object_creation_date,
"object_raw_origin_data.register_sales.sale_date" AS transaction_date,
"object_raw_origin_data.register_sales.total_price"
+ "object_raw_origin_data.register_sales.total_tax" AS transaction_gross_value,
"object_raw_origin_data.register_sales.total_price" AS transaction_net_value,
'goods-service-transaction' AS object_class,
'point-of-sale' AS object_origin_category,
'offline' AS object_origin_type,
object_origin AS object_origin,
"object_raw_origin_data.register_sales.invoice_number" AS transaction_reference,
"object_raw_origin_data.register_sales.status" AS transaction_status,
'GBP' AS transaction_currency,
"object_raw_origin_data.register_sales.sale_products.name" AS 'line_items.item_name'
FROM Vend_raw_transactions
`)
The query above works all except the last line which creates an object in the document called line_items but it isn't an array. The source is also an array.
Below is the Mongo script it creates for me:
db.Vend_raw_transactions.aggregate(
[{
"$project": {
"object_origin": "$object_origin",
"company": "$party_uuid",
"connection": "$connection_uuid",
"object_creation_date": "$object_created",
"transaction_date": "$object_raw_origin_data.register_sales.sale_date",
"transaction_gross_value": {
"$add": [
"$object_raw_origin_data.register_sales.total_price",
"$object_raw_origin_data.register_sales.total_tax"
]
},
"transaction_net_value":
"$object_raw_origin_data.register_sales.total_price",
"object_class": "goods-service-transaction",
"object_origin_category": "point-of-sale",
"object_origin_type": "offline",
"transaction_reference":
"$object_raw_origin_data.register_sales.invoice_number",
"transaction_status": "$object_raw_origin_data.register_sales.status",
"transaction_currency": "GBP",
"line_items.item_name":
"$object_raw_origin_data.register_sales.sale_products.name"
}
}])
Does anyone know why the last line isn't working for me?
"line_items.item_name": "$object_raw_origin_data.register_sales.sale_products.name"
I'm pretty sure I'm missing an [*] somewhere. Thanks, Matt
EDITED TO ADD example of Vend Transaction
{
"object_category" : "application",
"object_type" : "register-sales-24-months",
"object_origin" : "vend",
"tenant_uuid" : "00000000-0000-0009-9999-999999999999",
"party_uuid" : "8d519765-05d2-469f-ad35-d7a22fa9df2f",
"subscription_uuid" : "0",
"connection_uuid" : "6ed9bd79-d9c5-4296-a821-7e15b1c69e6c",
"status" : "",
"object_created" : ISODate("2018-03-15T21:40:57.158+0000"),
"object_raw_origin_data" : {
"pagination" : {
"results" : NumberInt(75964),
"page" : NumberInt(1),
"page_size" : NumberInt(200),
"pages" : NumberInt(380)
},
"register_sales" : {
"id" : "776a66f2-993c-b372-11e8-26f9bbe253f4",
"source" : "USER",
"source_id" : "",
"register_id" : "02dcd191-ae55-11e6-edd8-ec8dce1d9e1c",
"market_id" : "3",
"customer_id" : "02d59481-b67d-11e5-f667-b08185e8f6d5",
"customer_name" : "",
"customer" : {
"id" : "02d59481-b67d-11e5-f667-b08185e8f6d5",
"name" : "",
"customer_code" : "WALKIN",
"customer_group_id" : "02d59481-b67d-11e5-f667-b08185e893f8",
"customer_group_name" : "All Customers",
"updated_at" : "2016-01-01 12:16:44",
"deleted_at" : "",
"balance" : "0",
"year_to_date" : "0",
"date_of_birth" : "",
"sex" : "",
"custom_field_1" : "",
"custom_field_2" : "",
"custom_field_3" : "",
"custom_field_4" : "",
"note" : "",
"contact" : {
}
},
"user_id" : "02d59481-b655-11e5-f667-dca974edc4ea",
"user_name" : "Alvaro Velosa",
"sale_date" : "2018-03-13 20:04:57",
"created_at" : "2018-03-13 20:05:08",
"updated_at" : "2018-03-13 20:05:08",
"total_price" : 3.5,
"total_cost" : 2.74,
"total_tax" : NumberInt(0),
"tax_name" : "No Tax",
"note" : "",
"status" : "CLOSED",
"short_code" : "newa6f",
"invoice_number" : "Masonic2107Temple",
"accounts_transaction_id" : "",
"return_for" : "",
"register_sale_products" : [
{
"id" : "776a66f2-993c-b372-11e8-26f9cbf10f10",
"product_id" : "02dcd191-ae55-11e7-f130-9d4f4bcd91b1",
"register_id" : "02dcd191-ae55-11e6-edd8-ec8dce1d9e1c",
"sequence" : "0",
"handle" : "LAGERDRAUGHT300",
"sku" : "10287",
"name" : "LAGER DRAUGHT £3.00",
"quantity" : NumberInt(1),
"price" : 3.5,
"cost" : 2.74,
"price_set" : NumberInt(0),
"discount" : NumberInt(0),
"loyalty_value" : NumberInt(0),
"tax" : NumberInt(0),
"tax_id" : "02d59481-b67d-11e5-f667-b08185ec2871",
"tax_name" : "No Tax",
"tax_rate" : NumberInt(0),
"tax_total" : NumberInt(0),
"price_total" : 3.5,
"display_retail_price_tax_inclusive" : "0",
"status" : "CONFIRMED",
"attributes" : [
{
"name" : "line_note",
"value" : ""
}
]
}
],
"totals" : {
"total_tax" : NumberInt(0),
"total_price" : 3.5,
"total_payment" : 3.5,
"total_to_pay" : NumberInt(0)
},
"register_sale_payments" : [
{
"id" : "776a66f2-993c-b372-11e8-26f9cd75e9aa",
"payment_type_id" : "1",
"register_id" : "02dcd191-ae55-11e6-edd8-ec8dce1d9e1c",
"retailer_payment_type_id" : "02d59481-b655-11e5-f667-b0a23bc0e7bc",
"name" : "Cash",
"label" : "Account Customer",
"payment_date" : "2018-03-13 20:04:57",
"amount" : NumberInt(10)
},
{
"id" : "776a66f2-993c-b372-11e8-26f9cd7a3096",
"payment_type_id" : "1",
"register_id" : "02dcd191-ae55-11e6-edd8-ec8dce1d9e1c",
"retailer_payment_type_id" : "02d59481-b655-11e5-f667-b0a23bc0e7bc",
"name" : "Cash",
"label" : "Account Customer",
"payment_date" : "2018-03-13 20:04:57",
"amount" : -6.5
}
]
}
}
}
Use the $map operator to shape the field to an array by mapping the array elements to the item_name key:
"line_items": {
"$map": {
"input": "$object_raw_origin_data.register_sales.register_sale_products",
"as": "product",
"in": { "item_name": "$$product.name" }
}
}
Output
"line_items" : [
{
"item_name" : "LAGER DRAUGHT £3.00"
}
]

Mongo matching only where first element of array has certain field value

I have a query below that extracts a couple of values from a large nested document. It tells me the user id and the first item name for each order.
This works fine, however I want it to only return the record where the first item's name is not null and is not blank. I can't figure out how to add a second query to the $match operator below to achieve this
db.getCollection('Orders').aggregate
([
{ $match : { "Items.1" : { $exists : true }}, ???},
{ $project: {
_id:0,
'UserId': '$User.EntityId',
'ItemName': {$arrayElemAt: ['$Items.Details.ItemName', 0]}
}
}
]);
Edited to show sample document
{
"_id" : "order-666156",
"State" : "ValidationFailed",
"LastUpdated" : {
"DateTime" : ISODate("2017-09-26T08:54:16.241Z"),
"Ticks" : NumberLong(636420128562417375)
},
"SourceOrderId" : "666156",
"User" : {
"EntityId" : NumberLong(34450),
"Name" : "Bill Baker",
"Country" : "United States",
"Region" : "North America",
"CountryISOCode" : "US",
},
"Region" : null,
"Currency" : null,
"Items" : [
{
"ClientOrderId" : "18740113",
"OrigClientOrderId" : "18740113",
"Quantity" : NumberDecimal("7487.0"),
"TransactDateTime" : {
"DateTime" : Date(-62135596800000),
"Ticks" : NumberLong(0)
},
"Text" : null,
"LocateRequired" : false,
"Details" : {
"ItemName" : "Test Item 1",
"ItemCost" : 1495.20
}
},
{
"ClientOrderId" : "18740116",
"OrigClientOrderId" : "18740116",
"Quantity" : NumberDecimal("241.0"),
"TransactDateTime" : {
"DateTime" : Date(-62135596800000),
"Ticks" : NumberLong(0)
},
"Text" : null,
"LocateRequired" : false,
"Details" : {
"ItemName" : "Test Item 2",
"ItemCost" : 2152.64
}
}
]
}
You need to add the two conditions to your existing $match (not null and not blank) to check the Items as:
$match : { "Items.1" : { $exists : true, "$ne": null,"$ne":""}
If you want to check the element Items[0].Details.ItemName you can doing using the operator $and
{ $match : {
$and: [
{"Items.1" : { $exists : true }},
{"Items.Details.ItemName" : { $ne : null}},
{"Items.Details.ItemName" : { $ne : ""}},
]
}},

Mongoose Query: Find an element inside an array

Mongoose/Mongo noob here:
My Data
Here is my simplified data, each user has his own document
{ "__v" : 1,
"_id" : ObjectId( "53440e94c02b3cae81eb0065" ),
"email" : "test#test.com",
"firstName" : "testFirstName",
"inventories" : [
{ "_id" : "active",
"tags" : [
"inventory",
"active",
"vehicles" ],
"title" : "activeInventory",
"vehicles" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0069" ),
"tags" : [
"vehicle" ],
"details" : [
{ "_id" : ObjectId( "53440e94c02b3cae81eb0066" ),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms" } ] } ] },
{ "title" : "soldInventory",
"_id" : "sold",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] },
{ "title" : "deletedInventory",
"_id" : "deleted",
"vehicles" : [],
"tags" : [
"inventory",
"sold",
"vehicles" ] } ] }
As you can see, each user has an inventories property that is an array that contains 3 inventories (activeInventory, soldInventory and deletedInventory)
My Query
Given an user's email a a vehicle ID, i would like my query to go through find the user's activeInventory and return just the vehicle that matches the ID. Here is what I have so far:
user = api.mongodb.userModel;
ObjectId = require('mongoose').Types.ObjectId;
return user
.findOne({email : params.username})
.select('inventories')
.find({'title': 'activeInventory'})
//also tried
//.where('title')
//.equals('activeInventory')
.exec(function(err, result){
console.log(err);
console.log(result);
});
With this, result comes out as an empty array. I've also tried .find('inventories.title': 'activeInventory') which strangely returns the entire inventories array. If possible, I'd like to keep the chaining query format as I find it much more readable.
My Ideal Query
return user
.findOne({email : params.username})
.select('inventories')
.where('title')
.equals('activeInventory')
.select('vehicles')
.id(vehicleID)
.exec(cb)
Obviously it does not work but it can give you an idea what I'm trying to do.
Using the $ positional operator, you can get the results. However, if you have multiple elements in the vehicles array all of them will be returned in the result, as you can only use one positional operator in the projection and you are working with 2 arrays (one inside another).
I would suggest you take a look at the aggregation framework, as you'll get a lot more flexibility. Here's an example query for your question that runs in the shell. I'm not familiar with mongoose, but I guess this will still help you and you'd be able to translate it:
db.collection.aggregate([
// Get only the documents where "email" equals "test#test.com" -- REPLACE with params.username
{"$match" : {email : "test#test.com"}},
// Unwind the "inventories" array
{"$unwind" : "$inventories"},
// Get only elements where "inventories.title" equals "activeInventory"
{"$match" : {"inventories.title":"activeInventory"}},
// Unwind the "vehicles" array
{"$unwind" : "$inventories.vehicles"},
// Filter by vehicle ID -- REPLACE with vehicleID
{"$match" : {"inventories.vehicles._id":ObjectId("53440e94c02b3cae81eb0069")}},
// Tidy up the output
{"$project" : {_id:0, vehicle:"$inventories.vehicles"}}
])
This is the output you'll get:
{
"result" : [
{
"vehicle" : {
"_id" : ObjectId("53440e94c02b3cae81eb0069"),
"tags" : [
"vehicle"
],
"details" : [
{
"_id" : ObjectId("53440e94c02b3cae81eb0066"),
"year" : 2007,
"transmission" : "Manual",
"price" : 1000,
"model" : "Firecar",
"mileageReading" : 50000,
"make" : "Bentley",
"interiorColor" : "blue",
"history" : "CarProof",
"exteriorColor" : "blue",
"driveTrain" : "SWD",
"description" : "test vehicle",
"cylinders" : 4,
"mileageType" : "kms"
}
]
}
}
],
"ok" : 1
}
getting the chaining query format ... i dont know how to parse it but, what you are searching for is projection, you should take a look to http://docs.mongodb.org/manual/reference/operator/projection/
it would probably look like this :
user.findOne({email: params.username}, {'inventories.title': {$elemMatch: "activeInventory", 'invertories.vehicle.id': $elemMatch: params.vehicleId}, function(err, result) {
console.log(err);
console.log(result);
})

Resources