Mongodb subquery in insert - mongodb

I search for make something like :
insert into B (col)
select id from anotherCollection limit 1
I test this, but I suspected it was not going to work :
db.B.insert([
{
"a": "lores ipsum",
"b": [
db.getCollection('anotherCollection').find({},{_id:1}).limit(1)
]
}
]);
is it necessary to use a projection ?

You can't do it in mongo dbbut in javascript or python like this
var a = db.getCollection('anotherCollection').find({},{_id:1}).limit(1)
db.B.insert([
{
"a": "lores ipsum",
"b": a
}
]);

Related

How to show specific column in mongo db collection

I tried to show particular columns in mongodb colletion.but its not working.how to show particular columnns.
user_collection
[{
"user_name":"hari",
"user_password":"123456"
}]
find_query
db.use_collection.find({},{projection:{user_name:1}})
I got output
[{
"user_name":"hari",
"user_password":"123456"
}]
Excepted output
[{
"user_name":"hari",
}]
Try:
db.use_collection.find({}, {user_name:1, _id: 0 })
In that way you get the field user_name and exclude the _id.
Extra info:
project fields and project fields excluding the id
With aggregate:
db.use_collection.aggregate( [ { $project : { _id: 0, user_name : 1 } } ] )
You can try this
Mongo query:
db.users.aggregate([
{
"$project":
{
"_id": 0,
"first_name": 1,
}
}
])
Or in ruby (Mongoid)
User.collection.aggregate(
[
"$project":
{
"_id": 0,
"first_name": 1,
}
]
)
If you try to inspect the record, you can convert it into an array first (e.g. User.collection.aggregate(...).to_a)
You can use the official mongodb reference when writing in Mongoid, usually you just need to use double quote on the property name on the left hand side, to make it work on Mongoid.
Try:
db.use_collection.find({}, {user_password:0, _id: 0 ,user_name:1 })

PyMongo(3.6.1) - db.collection.aggregate(pipeline) NOT WORKING

I'm having trouble with PyMongo, I have been googling for hours, but found no solution.
I'm working with some Python Scripts just to practice with MongoDb, which is running on my local machine. I have populated my mongoDb instance with one database "moviesDB", which contains 3 different collections:
1.Movies collection, here is an example of a document from this coll:
{'_id': 1,
'title': 'Toy Story (1995)',
'genres': ['Adventure', 'Animation', 'Children', 'Comedy', 'Fantasy'],
'averageRating': 3.87,
'numberOfRatings': 247,
'tags': [
{'_id': ObjectId('5b04970b87977f1fec0fb6e9'),
'userId': 501,
'tag': 'Pixar',
'timestamp': 1292956344}
]
}
2.Ratings collection, which looks like this:
{ '_id':ObjectId('5b04970c87977f1fec0fb923'),
'userId': 1,
'movieId': 31,
'rating': 2.5,
'timestamp': 1260759144}
3.Tags collection, that I won't use here, so it's not important.
Now, what I'm trying to do is: given a user (in this example, user 1), find all the genres of movies that he rated and per each genre list all the movieIds regarding that genre.
Here's my code:
"""
This query basically retrieves movieIds,
so from the result list of several documents like this:
{
ObjectId('5b04970c87977f1fec0fb923'),
'userId': 1,
'movieId': 31,
'rating': 2.5,
'timestamp': 1260759144},
retrieves only an array of integers, where each number represent a movie
that the user 1 rated."""
movies_rated_by_user = list(db.ratings.distinct(movieId, {userId: 1}))
pipeline = [
{"$match": {"_id ": {"$in": movies_rated_by_user}}},
{"$unwind": "$genres"},
{"$group": {"_id": "$genres", "movies": {"$addToSet": "$_id"}}}]
try:
"""HERE IS THE PROBLEM, SINCE db.movies.aggregate() RETURNS NOTHING!
so the cursor is empty."""
cursor = db.movies.aggregate(pipeline, cursor={})
except OperationFailure:
print("Something went Wrong", file=open("operations_log.txt", "a"))
print(OperationFailure.details, file=open("operations_log.txt", "a"))
sys.exit(1)
aggregate_genre = []
for c in cursor:
aggregate_genre.append(c)
print(aggregate_genre)
The point is that the aggregate function on the movies collection retrieves NOTHING, whereas it really should, since I tried this query on the MongoShell and it worked just fine. Here's how the mongoDB shell-query looks like:
db.movies.aggregate(
[
{$match:{_id : {$in: ids}}},
{$unwind : "$genres"},
{$group :
{
_id : "$genres",
movies: { $addToSet : "$_id" }}}
]
);
Where the 'ids' variables is defined like this, just like the movies_rated_by_user variable in the code:
ids= db.ratings.distinct("movieId", {userId : 1});
The result from the aggregate method looks like this (this is what the aggregate_genre variable in the code, should contain):
{ "_id" : "Western", "movies" : [ 3671 ] }
{ "_id" : "Crime", "movies" : [ 1953, 1405 ] }
{ "_id" : "Fantasy", "movies" : [ 2968, 2294, 2193, 1339 ] }
{ "_id" : "Comedy", "movies" : [ 3671, 2294, 2968, 2150, 1405 ] }
{ "_id" : "Sci-Fi", "movies" : [ 2455, 2968, 1129, 1371, 2105 ] }
{ "_id" : "Adventure", "movies" : [ 2193, 2150, 1405, 1287, 2105, 2294,
2968, 1371, 1129 ] }
Now the problem is the aggregate method, is there any error with the pipeline string??
PLEASE HELP!!
Thank you
I think you need to cast the cursor to a list before iterating through it. Hope this helps.
cursor = list(db.movies.aggregate(pipeline, cursor={}))

update nested arrays from flat file

Seems this question is a very popular one, but I haven't found an answer (or at least not one I was able to understand).
I'm having a flat file that I would like to store in Mongo using some nestings. Though it is relatively easy to achieve with an insert and unique content I have the need to update the content on a regular base, so would need to be able to use the update commands also.
My flat file looks as follows :
Model,Category,Organisation,CountryCode,CountryWarranty,PeriodCode,PeriodQty
Model1,Category1,Org1,Code1,2Y,201707,1
Model1,Category1,Org1,Code1,2Y,201708,2
Model1,Category1,Org1,Code1,1Y,201709,3
Model1,Category1,Org1,Code2,2Y,201707,7
Model1,Category1,Org1,Code2,2Y,201708,8
Model1,Category1,Org1,Code2,5Y,201709,7
Model1,Category1,Org2,Code3,2Y,201707,5
Model1,Category1,Org2,Code3,4Y,201708,6
Model1,Category1,Org2,Code3,2Y,201709,7
...
Model_n,Category_n,Org_n,Code_n,3Y,201802,20
and what I like to achieve is the following :
{
"_id": "Model1",
"Model_category": "Category1",
"Product_Sales": [
{
"Organisation": "Org1",
"Country": [
{
"Code": "Code1",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 1},
{"Code": 201708,"Qty": 2},
{"Code": 201709,"Qty": 3}
]
}, {
"Code": "Code2",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 7},
{"Code": 201708,"Qty": 8},
{"Code": 201709,"Qty": 7}
]
}
]
}, {
"Organisation": "Org2",
"Country": [
{
"Code": "Code3",
"Guarantee_Years": "2Y",
"Period": [
{"Code": 201707,"Qty": 5},
{"Code": 201708,"Qty": 6},
{"Code": 201709,"Qty": 7}
]
}
]
}
]
}
Below a snippet of what I tried, note that the syntax is specific to my development environment so I know it is not workable or proper mongo, but it's about the basic idea. Any example using the console will do fine for me
concat("{update: "master_Sales",
updates: [
{
q:{"_id":", %{_id},""},
u:{$addToSet: {
"Product_Sales.Organisation": "", %{org}, "",
"Product_Sales.Organisation.Country": [
-- more here but have no clue --
]
}}
, upsert: true}
]}"
)
Adding my organisations works fine, but as soon as I want to add a second level (nested within an org) it goes wrong.
So in essence I want to be able to add this flat content to my Mongo in a nested array structure, and each time one of the values is changed in the future (say the quantity is updated, or a new country is added) that the line is added / updated so I am not forced to do a full refresh and insert each time a line is modified.
What would be the best approach to deal with this?
say the quantity is updated, or a new country is added
You can try below update query in 3.6 mongo version.
For updating Qty for Organisation/Country Code/Period Code - Org1/Code1/201707
db.collection.update(
{ },
{ "$set": { "Product_Sales.$[org].Country.$[country].Period.$[period].Qty" : 2 } },
{ arrayFilters: [ { "org.organisation": "Org1" }, { "country.Code": "Code1" }, { "period.Code": 201707 } ] }
)
For adding new Country to Organisation Org2
db.collection.update(
{ },
{ "$push": { "Product_Sales.$[org].Country" : {"Code": "Code4","Guarantee_Years": "2Y"} } },
{ arrayFilters: [ { "org.organisation": "Org2"} ] }
)
Can be simplified to
db.collection.update(
{ "org.organisation": "Org2"},
{ "$push": { "Product_Sales.$.Country" : {"Code": "Code4","Guarantee_Years": "2Y"} } }
)

Mongo find in hash

Suppose I have several documents like so
{
title: 'blah',
value: {
"A": {property: "foo"},
"B": {property: "bar"},
"C": {property: "foo"},
"D": {property: "foo"}
}
}
{
title: 'blah2',
value: {
"A": {property: "bar"},
"B": {property: "bar"},
"C": {property: "bar"},
"D": {property: "foo"}
}
}
What mongodb query will get me all of the documents / hash keys that have {property: "foo"}
(I know this can be done using js after the query, but can it be done within the query itself?)
The trouble is that there's no wildcard for object keys (see https://jira.mongodb.org/browse/SERVER-267), so you wouldn't be able to do this without listing all of the keys in your "value". That might be an option if you know what all of the keys are, but I imagine you don't.
If you converted "value" to an array rather than an object, you could do a query easily (which would return the documents, not the hash keys).
As the first answer says, there is nothing in the mongodb query language that would allow you to do this type of query.
You might want to consider altering your schema to make value an array like this:
value: [
{ name : "A", property : "bar" },
{ name : "B", property : "bar" },
{ name : "C", property : "bar" },
{ name : "D", property : "foo" }
]
Then you could index on value.property and run a query on value.property = "foo".

Get a list of all unique tags in mongodb

I am beginning with mongodb and have a collection with documents that look like the following
{
"type": 1,
"tags": ["tag1", "tag2", "tag3"]
}
{
"type": 2,
"tags": ["tag2", "tag3"]
}
{
"type": 3,
"tags": ["tag1", "tag3"]
}
{
"type": 1,
"tags": ["tag1", "tag4"]
}
With this, I want a set of all the tags for a particular type. For example, for type 1, I want the set of tag1, tag2, tag3, tag4 (any order).
All I could think of is to get the tags and add them to a set in python, but I wanted to know if there is a way to do it with mongodb's mapreduce or something else. Please advise.
If you just want a (distinct) list of the tags then using distinct will be best. Map/Reduce will be slower and can't use an index for the javascript part.
http://docs.mongodb.org/manual/reference/method/db.collection.distinct/
db.coll.distinct("tags", {type:1}) Will return a set of tags for type=1.
You are right, a Map/Reduce might work for what you are trying to accomplish, but a Set might be faster and less code.
> m = function() {
... for (var tag in this.tags) {
... emit(this.tags[tag], 1);
... }
... }
> r = function(key, values) {
... return 1;
... }
> db.tags.mapReduce(m, r).find()
{ "_id" : "tag1", "value" : 1 }
{ "_id" : "tag2", "value" : 1 }
{ "_id" : "tag3", "value" : 1 }