push to list based mongodb - mongodb

I would like to update the following structure:
record = {'_id':some_id,
'status': { 1 : {
'events' : [a,b,c ],
'other_stuff' : { }
}
{ 2 : {
'events' : [a,b,c ] },
'other_stuff' : { }
} ,
}
,
'other_key':{...}
}
Now what I want to do is, with status code = 3 and and event list = ['x','y','z'] I would like to have:
record = {'_id':some_id,
'status': { 1 : {
'events' : [a,b,c],
'other_stuff' : { }
},
{ 2 : {
'events' : [a,b,c ] },
'other_stuff' : { }
} ,
{ 3 : {
'events' : [x,y,z ] },
} ,
}
,'other_key':{...}
}
Is there a fast way to get this done without too much maneuvering?

You can use the dot notation to specify the embedded document in your $set as follows:
db.collection.updateOne(
{ "_id": ObjectId("5852bc9eade47a3353ff01d0") },
{
"$set": {
"status.3": {
"events" : ["x","y","z"]
}
}
}
)

Related

How to remove an object which is inside [nested] of an object which is in an object array [MongoDB]?

I have a document:
{
"Name": "Downhill 3",
"Apartments": [
{
"Yardage": 55.5,
"Owner": {
"name" : "Timothy",
"surname" : "Notclement",
"phone" : 555666777
}
},
{
"Yardage": 70,
"Owner": {
"name" : "Anya",
"surname" : "Joylor-Tay",
"phone" : 555111000
}
}
]
}
It represents "all" apartments at some street.
I want to delete one entry from Apartments array, let's say the one which is owned by Anya, by specifying it by something like this Apartments.Owner.name:"Anya".
How can I perform such an operation? I tried to $pull and to $unset, but nothing worked. Now I came across findAndModify (docs here) and possibility to use an aggregation pipeline in the update field, but can't really figure out how to form a query.
Mongo commands I tried:
db.ApartCollection.update( { "_id":ObjectId("example123") }, { $unset: { "Apartments.Owner.name" : "Anya" } } )
db.ApartCollection.update( { "_id":ObjectId("example123") }, { $unset: { Apartments: { "Owner.name" : "Anya" } } } )
db.ApartCollection.update( { "_id":ObjectId("example123") }, { $pull: { Apartments: { "Owner.name" : "Anya" } } } )
db.Dokumenty.update( { "_id":ObjectId("61881be8dd6d25184a3b6c3f") }, { $pull: { "Apartments.Owner.name": "Anya" } } )
^This one doesn't even ?compile? It returns error:
Cannot use the part (Owner) of (Apartments.Owner.name) to traverse the element ({Apartments:...blah blah

PyMongo bulk_write UpdateOne only runs last operation

Got a weird bug that I can't quite figure out.
I have some pymongo code that looks like this:
from pymongo import UpdateOne
client = pymongo.MongoClient()
...
def update_image_locations(user_key, dataset_key, preset_name,
keys_and_coords):
db = docdb_client.db
col = db.col
operations = []
query = {'ownerKey': user_key, 'imageInfo.datasetKey': dataset_key}
for key_and_coords in keys_and_coords:
query['key'] = key_and_coords['key']
operations.append(
pymongo.UpdateOne(
query, {
'$set': {
'imageInfo.presets.%s.coords' % preset_name:
key_and_coords['coords']
}
}))
print(operations)
if len(operations) > 0:
print(col.bulk_write(operations, ordered=False).bulk_api_result)
# This section fails with a KeyError.
cursor = col.find({
'ownerKey': user_key,
'imageInfo.datasetKey': dataset_key
}, {'imageInfo': 1}
)
for doc in cursor:
print(doc['imageInfo']['presets'])
If I print out the bulk_write output, I get the following.
{'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 0, 'nUpserted': 0, 'nMatched': 65, 'nModified': 65, 'nRemoved': 0, 'upserted': []}
which as far as I can tell is exactly what I expect.
However, I get KeyError failures for all but the last document in the collection when I try to iterate through the documents that should ostensibly have the new field. If I then go into the actual mongodb shell, I can confirm that only the last operation from the bulk_write seems to have actually gone off.
Based on the bulk_api_result I would expect that all of the documents would be updated, instead of only the last one. What's going on?
EDIT:
As requested, before and after queries. I'm not showing the full doc because there's a lot of vector embedding info that's going to muddle things.
Query:
> db.user_uploads.find({}, {'imageInfo.presets': 1})
Before:
{ "_id" : ObjectId("6074792104cc23375a8f979a"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979b"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979c"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979d"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979e"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979f"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a0"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a1"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a2"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a3"), "imageInfo" : { } }
After:
{ "_id" : ObjectId("6074792104cc23375a8f979a"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979b"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979c"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979d"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979e"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f979f"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a0"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a1"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a2"), "imageInfo" : { } }
{ "_id" : ObjectId("6074792104cc23375a8f97a3"), "imageInfo" : { "presets" : { "preset_one" : { "coords" : [ 2.229365348815918, 1.4654869735240936 ] } } } }
Turns out the answer has to do with how the query is constructed. Specifically, this works:
for key_and_coords in keys_and_coords:
query = {'key': key_and_coords['key']}
operations.append(
pymongo.UpdateOne(
query, {
'$set': {
'imageInfo.presets.%s.coords' % preset_name:
key_and_coords['coords']
}
}))
and this fails:
query = {}
for key_and_coords in keys_and_coords:
query['key'] = key_and_coords['key']
operations.append(
pymongo.UpdateOne(
query, {
'$set': {
'imageInfo.presets.%s.coords' % preset_name:
key_and_coords['coords']
}
}))
I think what's happening here is some async javascript-esque magic, where the query object is passed by reference to the bulk operation which then executes them once all of the bulk operations are in place. Since the query is passed by reference, the actual key value gets overwritten each time until the last one (which is also why only the last object is updated). Unfortunately this was tough to catch because printing out the queries and the operations both looked fine, but the async kicked in at execution. Still, not really an issue with pymongo after all.
Thanks to everyone who responded!

Remove by _id inside a nested array, inside of a collection

this is my mongoDb footballers collection :
[
{
"_id" : ObjectId("5d83b4a7e5511f28847f1884"),
"prenom" : "djalil",
"pseudo" : "dja1000",
"email" : "djalil#gmail.com",
"selectionned" : [
{
"_id" : "5d83af3be5511f28847f187f",
"role" : "footballeur",
"prenom" : "Gilbert",
"pseudo" : "Gilbert",
},
{
"_id" : "5d83b3d5e5511f28847f1883",
"role" : "footballeur",
"prenom" : "Xavier",
"pseudo" : "xav4544",
}
]
},
{
"_id" : ObjectId("5d83afa8e5511f28847f1880"),
"prenom" : "Rolande",
"pseudo" : "Rolande4000",
"email" : "rolande#gmail.com",
"selectionned" : [
{
"_id" : "5d83b3d5e5511f28847f1883",
"role" : "footballeur",
"prenom" : "Xavier",
"pseudo" : "xav4544",
}
]
}
}
How could I delete each selectionned people who has the 5d83b3d5e5511f28847f1883 _id through all of the collection?
I do need xavier to deseappear from any 'selectionned' array , just like doing a 'delete cascade' in SQL language
This is what I've tried with no luck :
function delete_fb_from_all(fb){
var ObjectId = require('mongodb').ObjectID; //working
var idObj = ObjectId(fb._id); //working
try {
db.collection('footballers').remove( { "selectionned._id" : idObj } );
console.log('All have been erased');
} catch (e) {
console.log(e);
}
}
And this too is not working :
db.collection('footballers.selectionned').remove( { "_id" : idObj } );
i really dont know how to do this.
i'm trying out this right now :
db.collection.update({'footballers.selectionned': idObj }, {$pull: {footballers:{ selectionned: idObj}}})
This is the error :
TypeError: db.collection.update is not a function
I think that the solution is maybe there :
https://docs.mongodb.com/manual/reference/operator/update/pull/#pull-array-of-documents
EDIT 1
i'm currently trying ou this :
var ObjectId = require('mongodb').ObjectID; //working
var idObj = ObjectId(fb._id); //working
try {
db.collection('footballers').update(
{ },
{ $pull: { selectionned: { _id: idObj } } },
{ multi: true }
)
} catch (e) {
console.log(e);
}
SOLVED :
Specifiying the email, it is now working, I guess the problem was comin from the _id field :
try {
db.collection('footballers').update(
{ },
{ $pull: { selectionned: { email: fb.email } } },
{ multi: true }
)
} catch (e) {
console.log(e);
}
Object ID :
The issue is may be on your object id creation. No need to make string-id with mongoDB object id.
// No need
var ObjectId = require('mongodb').ObjectID;
var idObj = ObjectId(fb._id);
// do as normal string
db.collection('footballers').remove( { "selectionned._id" : fb._id } );

MongoDB: Rename Field in A Collection (Document and Subdocuments)

Using MongoDB 3.6
I have document structure like below
`
{
"_id" : ObjectId("5d88"),
"Equipments" : [
{
"InnerEquipments" : {
"AssetId" : 678
},
"AssetID" : 456
}
],
"AssetID" : 123
}
I want rename the field from AssetID/AssetId to Asset_ID at all levels.
How can I do this with mongo shell.
The following code can do the trick:
// Getting all documents from the collection
var data = db.collection.find({},{"_id":0}).toArray();
// Converting the data into JSON string
var string = JSON.stringify(data);
// Replacing all variations of assetid with Asset_ID
string = string.replace(/assetid/ig,"Asset_ID");
// Removing existing documents from collection
db.collection.remove({});
// Converting the string back to JSON array and inserting it into the DB
db.collection.insertMany(JSON.parse(string));
Before:
{
"_id" : ObjectId("5d89e9ab0558a18dd9cfc03a"),
"Equipments" : [
{
"InnerEquipments" : {
"AssetId" : 678
},
"AssetID" : 456
}
],
"AssetID" : 123
}
After:
{
"_id" : ObjectId("5d89eea80558a18dd9cfc03b"),
"Equipments" : [
{
"InnerEquipments" : {
"Asset_ID" : 678
},
"Asset_ID" : 456
}
],
"Asset_ID" : 123
}
You need to make a script for this.
I have not tested it. Make changes accordingly.
db.collection.find({}).forEach(function(doc) {
if(doc['AssetID']) {
doc['Asset_ID'] = doc['AssetID'];
delete doc['AssetID'];
} else if (doc['AssetId']) {
doc['Asset_ID'] = doc['AssetId'];
delete doc['AssetId']
}
if(doc.Equipments && doc.Equipments.length) {
doc.Equipments.forEach(function(rec) {
if(rec['AssetID']) {
rec['Asset_ID'] = rec['AssetID'];
delete rec['AssetID'];
} else if (rec['AssetId']) {
rec['Asset_ID'] = rec['AssetId'];
delete rec['AssetId']
}
if(rec['InnerEquipments']['AssetID']) {
rec['InnerEquipments']['Asset_ID'] = rec['InnerEquipments']['AssetID'];
delete rec['InnerEquipments']['AssetID'];
} else if (rec['InnerEquipments']['AssetId']) {
rec['InnerEquipments']['Asset_ID'] = rec['InnerEquipments']['AssetId'];
delete rec['InnerEquipments']['AssetId']
}
})
}
db.collection.update({'_id':doc._id},doc);
});

Use index of object in MongoDB to return result

Below is a collection in mongodb. I need to return the bus_number given a start stop and an end stop. the constraint is that that the index of the end stop has to be greater than the index of the start stop.
So, given start=226 & end=229 the returned value should be 1A.
start=229 & end=226 should return nothing.
{
"_id" : ObjectId("59be068"),
"route" : "1A",
"route_patterns" : [
{
"route_pattern_id" : "00010001",
"route_stops" : [
{
"stop_id" : "226",
},
{
"stop_id" : "228"
},
{
"stop_id" : "229"
},
{
"stop_id" : "227"
}
]
}
]}
Edit:
my structure now looks like this:
{
"route":"1A",
"route_pattern_id":"00010001",
"route_stops":[
{
"stop_id":"226",
"stop_number":0
},
{
"stop_id":"228",
"stop_number":1
},
{
"stop_id":"229",
"stop_number":2
},
{
"stop_id":"227",
"stop_number":3
}
]
}
This way I am now using the stop_number. Not a clean solution.
This is what I have done:
entity_start = db.routes.find({
"route_patterns.route_stops.stop_id": str(start_stop)
})
dumps(entity_start)
start_buses = [routes['route'] for routes in entity_start]
entity_end = db.routes.find({
"route_patterns.route_stops.stop_id": str(end_stop)
})
end_buses = [routes['route'] for routes in entity_end]
set_two = set(start_buses)
set_one = set(end_buses)
return dumps(set_one.intersection(set_two))