Use $AND in MongoDB (querys) - database

I am starting to use the NoSQL database MongoDB and doing some courses of MongoDB.
I am trying to resolve two querys but I can't :(
Are the followings:
What is the name of the listing in the sample_airbnb.listingsAndReviews dataset that accommodates more than 6 people and has exactly 50 reviews?
db.listingsAndReviews.find({"$and": [{"accommodates" {"$gt": 6}}, {"reviews": {"$size": 50}}]}).count()
How many companies in the sample_training.companies dataset were either founded in 2004 and either have the social category_code or web category_code, or were founded in the month of October and also either have the social category_code or web category_code?
db.companies.find({"$and": [{"$or": ["foundation_year": 2004], ["founded_month": 10]}],[{"$or": ["category_code": "web"], ["category_code": "social"]}]}).count()
But any of these two querys works, what can I be doing wrong?
Thanks in advance!

MongoDB provides an implicit AND operation when specifying a comma separated list of expressions. You only need to use $AND if you are evaluating the same field.
For the first question you must use the number_of_reviews, like so:
{ number_of_reviews: 50, accommodates: { $gt: 6 } }
For the second question you must use the correct sintax for $OR, like so:
{ $and: [ { $or: [ { founded_year: 2004 }, { founded_month: 10 } ] }, { $or: [ { category_code: 'social'}, { category_code: 'web' } ] } ] }

This was the query that I used :
db.companies.find({ "$or" : [ {"founded_year" : 2004 , "$or" : [ {"category_code" : "social"} , {category_code : "web"} ] } , {"founded_month" : 10 , "$or" : [ {"category_code" : "social"} , {category_code : "web"} ] } ] }).count()
Answer was correct.

db.companies.find({"$and":[{"$or":[{"founded_year": 2004},{"founded_month": 10}]},{"$or":[{"category_code": "social"}, {"category_code": "web"}]}]}).count()

Related

MongoDB - Find is array exists within an object

I have a large collection of different products with various fields.
Once field is named 'ar_related'
This holds 0 or many different arrays. For example it could hold:
also_viewed, also_bought, bought_together, buy_after_viewing
Here is an example of a document:
{
"_id" : ObjectId("5a95cef390bd8fbf1c699d6d"),
"ar_asin" : "0078764343",
"ar_description" : "Brand new sealed!",
"ar_price" : 37.98,
"ar_imUrl" : "http://ecx.images-amazon.com/images/I/513h6dPbwLL._SY300_.jpg",
"ar_related" : {
"also_bought" : [
"B000TI836G",
"B003Q53VZC",
"B00EFFW0HC",
"B003VWGBC0",
"B003O6G5TW",
"B0037LTTRO",
"B002I098JE",
"B008OQTS0U",
"B005EVEODY",
"B008B3AVNE",
"B000PE0HBS",
"B00354NAYG",
"B0050SYPV2",
"B00503E8S2",
"B0050SY77E",
"B0022TNO7S",
"B0056WJA30",
"B0023CBY4E",
"B002SRSQ72",
"B005EZ5GQY",
"B004XACA60",
"B00273Z9WM",
"B004HX1QFY",
"B002I0K50U"
],
"bought_together" : [
"B002I098JE"
],
"buy_after_viewing" : [
"B0050SY5BM",
"B000TI836G",
"B0037LTTRO",
"B002I098JE"
]
},
"ar_salesRank" : {
"Video Games" : 28655
},
"ar_categories" : [
[
"Video Games",
"Xbox 360",
"Games"
]
]
}
What I am trying to achieve is to return (and count) all products which contain the 'bought_together' array within the ar_related object. Some products contain it and some do not.
I have tried a few different approaches, mostly with the $elemMatch operator but am having no luck. I am new to NoSQL as from a SQL background.
Any response will be appreciated.
Try this
db.getCollection('products').find({ "ar_related": {
$exists: true,
$elemMatch: { "bought_together": {$exists: true} }
}
})
After some painful research, Ive found this answer.
db.P14162135_products.find({
"ar_related.brought_together":{$exists: true}
}).count();
Thank you all for the responses

pull from mongo nested array

{
"partners" : [
{
"partnerId" : 5,
"topicIds" : [
"59de26f2e4b0f263704769e5"
]
},
{
"partnerId" : 45,
"topicIds" : [
"alpha",
"beta"
]
},
{
"partnerId" : 12345,
"topicIds" : [
"alpha"
]
}
]
}
I want to pull certain topicIds from specified partners.
So for example I want to pull alpha topic from partnerId = 45 (the entry should remain with topicIds = ["beta"]).
I tried:
db.mypartnercoll.update({}, {$pull:{"partners":{"partnerId":45, "topicIds":{"$in":["alpha"]}}}})
however this removes the entire partnerId = 45 entry. I will have a single partnerId value and multiple topicIds to pull.
instead of
db.mypartnercoll.update({}, {$pull:{"partners":{"partnerId":45, "topicIds":{"$in":["alpha"]}}}})
use
db.mypartnercoll.update({"partners.$.partnerId":"yourdesired_partnerId"},
{$pull:{"partners":{"partnerId":45, "topicIds":{"$in":["alpha"]}}}})
this is an update query so you can specify in the first {} a certain document or array element to operate on

Import Object of arrays from CSV to Neo4j

I have a collection in mongo that I need to migrate to Neo4j. To do that, I will export it to CSV. Then, I'll import the resultant CSV to Neo4j using Cypher. The documents from the collection have an object with an array that contains objects with arrays inside them. Take a look at the JSON above:
"services" : [
{
"max_id" : "646767779849326594",
"log" : [
{
"date" : 1443024000,
"steps" : 6
},
{
"date" : 1442512800,
"steps" : 1
}
],
"service" : "home_timeline"
},
{
"max_id" : 0.0,
"log" : [
{
"date" : 1443024000,
"steps" : 4
},
{
"date" : 1442512800,
"steps" : 1
}
],
"service" : "user_timeline"
},
{
"max_id" : 0.0,
"log" : [
{
"date" : 1443024000,
"steps" : 6
},
{
"date" : 1442512800,
"steps" : 1
}
],
"service" : "mentions_timeline"
}
]
How can I import this to Neo4 properly?? I already found a solution to import arrays. But I didn't find nothing similar to my problem. How should be the header of the CSV? How should be the Cypher code to get these objets??
You can use JSON as a parameter to a Cypher query. There are a few examples of this here and here.
With your example something like this:
WITH {json} AS data
UNWIND data.services AS service
// Insert data for each service.
MERGE (s:Service { "service_name": service.service})
SET s.max_id = service.max_id
FOREACH (log IN service.logs | CREATE (l:Log {date: log.date, steps: log.steps})<-[:LOGGED]-(s))
There is also a tool for translating data from MongoDB document data model to Neo4j property graph model that you might find useful: https://github.com/neo4j-contrib/neo4j_doc_manager

Getting subdocument element's count per index inside an array and updating the subdocument key - subdocument in array(IN MONGODB)

How to get subdocument element's count inside an array and how to update the subdocument's key in MongoDB
For eg, following is the whole doc stored in mongodb:
{
"CompanyCode" : "SNBN",
"EventCode" : "ET00008352",
"EventName" : "Sunburn Presents Avicii India Tour",
"TktDetail" : [
{
"Type" : "Category I",
"Qty" : {
"10-Dec" : {
"value" : 58
},
"11-Dec" : {
"value" : 83
},
"12-Dec" : {
"value" : 100
}
}
},
{
"Type" : "Category II",
"Qty" : {
"10-Dec" : {
"value" : 4
},
"11-Dec" : {
"value" : 7
},
"12-Dec" : {
"value" : 8
}
}
},
{
"Type" : "PRICE LEVEL 1",
"Qty" : {
"11-Dec" : {
"value" : 2
}
}
},
{
"Type" : "CatIV",
"Qty" : {
"18-Dec" : {
"value" : 20
}
}
}
],
"TransDate" : [
"10-Dec-2013",
"11-Dec-2013",
"12-Dec-2013",
],
"VenueCode" : "SNBN",
"VenueName" : "Sunburn",
"_id" : ObjectId("52452db273b92012c41ad612")
}
Here TktDetail is an array, inside which there is a Qty subdoc which contains multiple elements, I want to know how to get the elements count inside Qty per index?
For example, the 0th index of TktDetail array contains 1 Qty subdoc, which further has a element count of 3, whereas 3rd index has element count of 1 in Qty subdoc.
If I want to update the subdoc key, like, I want to update the date in Qty from "10-Dec" to "10-Dec-2013", how is it possible?
Thanks in advance, looking for a reply ASAP..
So the first thing here is that you actually asked two questions, being "how do I get a count of the items under Qty?" and "how can I change the names?". Now while normally unrelated I'm going to treat them as the same thing.
What you need to do is change your schema and in doing so I'm going to allow you to get the count of items and I'm going to encourage you to change those field names as well. Specifically you need a schema like this:
"TktDetail" : [
{
"Type" : "Category I",
"Qty" : [
{ "date": ISODate("2013-12-10T00:00:00.000Z") , "value" : 58 },
{ "date": ISODate("2013-12-11T00:00:00.000Z"), "value" : 83 },
{ "date": ISODate("2013-12-01T00:00:00.000Z"), "value" : 100 },
]
},
All the gory details are in my answer here to a similar question. But the problem basically is that when you use sub-documents in the way you have you are ruining your chances of doing any meaningful query operations on this, as to get at each element you must specify the full path to get there.
That answer has more detail, but the case is you really want an array. The trade-off, it's a little harder to update, especially considering you have nested arrays, but it's a lot easier to add and much easier to query.
Also, and related, change your dates to be dates and not strings. The strings, are no good for comparisons inside MongoDB. With them set as proper BSON dates (noting I clipped them to the start of day) you can compare, and query ranges and do useful things. Your application code will be happy to as the driver will return a real date object, rather than something you have to manipulate "both ways".
So once you have read through, understood and implemented this, on to counting:
db.collection.aggregate([
// Unwind the TktDetail array to de-normalize
{"$unwind": "$TktDetail"},
// Also Unwind the Qty array
{"$unwind": "$Qty" },
// Get some group information and count the entries
{"$group": {
"_id": {
"_id": "$_id,
"EventCode": "$EventCode",
"Type": "$TktDetail.Type"
},
"Qty": {"$sum": 1 }
}},
// Project nicely
{"$project": {
"_id": 0,
"EventCode": "$_id.EventCode",
"Type: "$_id.Type",
"Qty": 1,
}},
// Let's even sort it
{"$sort": { "EventCode": 1, "Qty" -1 }}
])
So that allowed us to get a count of the items in Qty for each EventCode by Type with the Qty ordered higest to lowest.
And that is not possible on your current schema without loading and traversing each document in code.
So there is the case. Now if you want to ignore this and just go about changing the sub-document key names, then you'll need to do remove the key and underlying document and replace with the new key name, using update:
db.collection.update(
{ EventCode: "ET00008352"},
{ $unset:{ "TktDetail.0.Qty.10-Dec": "" }}
)
db.collection.update(
{ EventCode: "ET00008352"},
{ $set:{ "TktDetail.0.Qty.10-Dec-2013": { value: 58 } }}
)
And you'll need to do that for every item that you have.
So you either work out that schema conversion or otherwise have a lot of work anyway in order to change the keys. For myself, I'd do it properly, and only do it once so I didn't run into the next problem later.

mongodb - adding the value in a field to the value in an embedded array

I have a document in MongoDB as below.
{
"CorePrice" : 1,
"_id" : 166,
"partno" : 76,
"parttype" : "qpnm",
"shipping" :
[
{
"shippingMethod1" : "ground",
"cost1" : "10"
},
{
"shippingMethod2" : "air",
"cost2" : "11"
},
{
"shippingMethod3" : "USPS",
"cost3" : "3"
},
{
"shippingMethod4" : "USPS",
"cost4" : 45
}
]
}
My goal is to add CorePrice (1) to cost4 (45) and retrieve the computed value as a new column "dpv". I tried using the below query. However I receive an error exception: $add only supports numeric or date types, not Array. I'm not sure why. Any kind of help will be greatly appreciated.
db.Parts.aggregate([
{
$project: {
partno: 1,
parttype: 1,
dpv: {$add: ["$CorePrice","$shipping.cost1"]}
}
},
{
$match: {"_id":{$lt:5}}
}
]);
When you refer to the field shipping.cost1 and shipping is an array, MongoDB does not know which entry of the shipping-array you are referring to. In your case there is only one entry in the array with a field cost1, but this can't be guaranteed. That's why you get an error.
When you are able to change your database schema, I would recommend you to turn shipping into an object with a field for each shipping-type. This would allow you to address these better. When this is impossible or would break some other use-case, you could try to access the array entry by numeric index (shipping.0.cost1).
Another thing you could try is to use the $sum-operator to create the sum of all shipping.cost1 fields. When there is only one element in the array with a field cost1, the result will be its value.
I am able to achieve this by divorcing the query into two as below.
var pipeline1 = [
{
"$unwind": "$shipping"
},
{
$project:{
partno:1,
parttype:1,
dpv:{
$add:["$CorePrice","$shipping.cost4"]
}
}
},
{
$match:{"_id":5}
}
];
R = db.tb.aggregate( pipeline );

Resources