def update(self, message, meta={}, message_query={}, meta_query={}, upsert=False): """ Updates a message. :Args: | message (ROS Message): The updated ROS message | meta (dict): Updated meta data to store with the message. | message_query (dict): A query to match the ROS message that is to be updated. | meta_query (dict): A query to match against the meta data of the message to be updated | upsert (bool): If True, insert the named message if it doesnt exist. :Return: | str, bool: The MongoDB ObjectID of the document, and whether it was altered by the update. """ # serialise the json queries to strings using json_util.dumps message_query_tuple = (StringPair( dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(message_query, default=json_util.default)), ) meta_query_tuple = (StringPair( dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(meta_query, default=json_util.default)), ) meta_tuple = (StringPair(dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(meta, default=json_util.default)), ) return self.update_srv(self.database, self.collection, upsert, StringPairList(message_query_tuple), StringPairList(meta_query_tuple), dc_util.serialise_message(message), StringPairList(meta_tuple))
def insert(self, message, meta={}, wait=True): """ Inserts a ROS message into the message storage. :Args: | message (ROS Message): An instance of a ROS message type to store | meta (dict): A dictionary of additional meta data to store in association with thie message. | wait (bool): If true, waits until database returns object id after insert :Returns: | (str) the ObjectId of the MongoDB document containing the stored message. """ # assume meta is a dict, convert k/v to tuple pairs meta_tuple = (StringPair(dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(meta, default=json_util.default)), ) serialised_msg = dc_util.serialise_message(message) if wait: return self.insert_srv(self.database, self.collection, serialised_msg, StringPairList(meta_tuple)).id else: msg = Insert(self.database, self.collection, serialised_msg, StringPairList(meta_tuple)) self.pub_insert.publish(msg) return True
def move_entries(self, move_before=None, delete_after_move=False, query=None): move_before = move_before or rospy.Duration(self.interval) if query is None: query = {} query = StringPairList(pairs=[ StringPair(first=MongoQueryMsgRequest.JSON_QUERY, second=json_util.dumps(query)) ]) goal = MoveEntriesGoal(database=self.database, collections=StringList(self.collections), move_before=move_before, delete_after_move=delete_after_move, query=query) self.replicate_ac.send_goal(goal, done_cb=self.done_cb, active_cb=self.active_cb, feedback_cb=self.feedback_cb) while not self.replicate_ac.wait_for_result( timeout=rospy.Duration(5.0)): if rospy.is_shutdown(): break elif self.monitor_network and not self.network_connected: rospy.loginfo( "disconnected wired network connection. canceling replication..." ) self.replicate_ac.cancel_all_goals()
def query(self, type, message_query = {}, meta_query = {}, single = False, sort_query = []): """ Finds and returns message(s) matching the message and meta data queries. :Parameters: | type (str): The ROS message type of the stored messsage to retrieve. | message_query (dict): A query to match the actual ROS message | meta_query (dict): A query to match against the meta data of the message | sort_query (list of tuple): A query to request sorted list to mongodb module | single (bool): Should only one message be returned? :Returns: | [message, meta] where message is the queried message and meta a dictionary of meta information. If single is false returns a list of these lists. """ # assume meta is a dict, convert k/v to tuple pairs for ROS msg type # serialise the json queries to strings using json_util.dumps message_tuple = (StringPair(dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(message_query, default=json_util.default)),) meta_tuple = (StringPair(dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(meta_query, default=json_util.default)),) if len(sort_query) > 0: sort_tuple = [StringPair(str(k), str(v)) for k, v in sort_query] else: sort_tuple = [] # a tuple of SerialisedMessages response = self.query_id_srv(self.database, self.collection, type, single, StringPairList(message_tuple), StringPairList(meta_tuple), StringPairList(sort_tuple)) # print response if response.messages is None: messages = [] metas = [] else: messages = map(dc_util.deserialise_message, response.messages) metas = map(dc_util.string_pair_list_to_dictionary, response.metas) if single: if len(messages) > 0: return [messages[0], metas[0]] else: return [None, None] else: return zip(messages,metas)
def _fill_slots(self, src, dest): for s in dest.__slots__: if s in src: if s == 'arguments': # special case for attributes for a in src[s]: sp = StringPair() self._fill_slots(a, sp) dest.arguments.append(sp) else: # a bit of a hacky way to check if we need to recurse... if str(type(dest.__getattribute__(s))).\ startswith('<class ') \ or type(dest.__getattribute__(s)) == dict: self._fill_slots(src[s], dest.__getattribute__(s)) elif type(dest.__getattribute__(s)) == list: dest.__getattribute__(s).extend(src[s]) else: dest.__setattr__(s, src[s])
def add_bool_argument(mdp_action, bool_arg): mdp_action.arguments.append( StringPair(first=Task.BOOL_TYPE, second=str(bool_arg)))
def add_duration_argument(mdp_action, duration_arg): mdp_action.arguments.append( StringPair(first=Task.DURATION_TYPE, second=str(duration_arg.to_sec())))
def add_time_argument(mdp_action, time_arg): mdp_action.arguments.append( StringPair(first=Task.TIME_TYPE, second=str(time_arg.to_sec())))
def add_object_id_argument(mdp_action, oid, msg_type): mdp_action.arguments.append( StringPair(first=msg_type._type, second=str(oid)))
def add_float_argument(mdp_action, float_arg): mdp_action.arguments.append( StringPair(first=Task.FLOAT_TYPE, second=str(float_arg)))
def add_int_argument(mdp_action, int_arg): mdp_action.arguments.append( StringPair(first=Task.INT_TYPE, second=str(int_arg)))
def add_string_argument(task, string_arg): task.arguments.append(StringPair(first=Task.STRING_TYPE, second=string_arg))
def add_object_id_argument(task, oid, msg_type): task.arguments.append(StringPair(first=msg_type._type, second=str(oid)))
def add_float_argument(task, float_arg): task.arguments.append(StringPair(first=Task.FLOAT_TYPE, second=str(float_arg)))
def add_time_argument(task, time_arg): task.arguments.append(StringPair(first=Task.TIME_TYPE, second=str(time_arg.to_sec())))
#therefore use std_msg types for standard data types like float, int, bool, string etc result = Bool(True) # we will store our results in a separate collection msg_store = MessageStoreProxy(collection='pose_results') # save the ids from each addition stored = [] stored.append([pose._type, msg_store.insert(pose)]) stored.append([point._type, msg_store.insert(point)]) stored.append([quaternion._type, msg_store.insert(quaternion)]) stored.append([result._type, msg_store.insert(result)]) # now store ids togther in store, addition types for safety spl = StringPairList() for pair in stored: spl.pairs.append(StringPair(pair[0], pair[1])) # and add some meta information meta = {} meta['description'] = "this wasn't great" meta['result_time'] = datetime.utcfromtimestamp( rospy.get_rostime().to_sec()) msg_store.insert(spl, meta=meta) # now let's get all our logged data back results = msg_store.query(StringPairList._type) for message, meta in results: if 'description' in meta: print 'description: %s' % meta['description'] print 'result time (UTC from rostime): %s' % meta['result_time'] print 'inserted at (UTC from rostime): %s' % meta['inserted_at']
type=str, default='{}', help='Only entries that are matched by the query are moved.') return p.parse_args(args) if __name__ == '__main__': rospy.init_node("mongodb_replicator_client") args = parse_args(rospy.myargv()[1:]) # validate parameters try: data = json_util.loads(args.query) query = StringPairList(pairs=[ StringPair(first=MongoQueryMsgRequest.JSON_QUERY, second=json_util.dumps(data)) ]) except: raise ValueError('The query is invalid') if args.move_before < 0: raise ValueError('move_before time must be >= 0') move_before = rospy.Duration(args.move_before) goal = MoveEntriesGoal(database=args.database, collections=StringList(args.collection), move_before=move_before, delete_after_move=args.delete_after_move, query=query) rospy.loginfo('Moves entries from (db: %s, cols: %s)' % (args.database, args.collection)) rospy.loginfo('before time: %s' % (rospy.Time.now() - move_before))
def add_int_argument(task, int_arg): task.arguments.append(StringPair(first=Task.INT_TYPE, second=str(int_arg)))
def add_string_argument(mdp_action, string_arg): mdp_action.arguments.append( StringPair(first=Task.STRING_TYPE, second=string_arg))
def query_messages_ros_srv(self, req): """ Returns t """ collection = self._mongo_client[req.database][req.collection] # build the query doc obj_query = self.to_query_dict(req.message_query, req.meta_query) # restrict results to have the type asked for obj_query["_meta.stored_type"] = req.type # TODO start using some string constants! rospy.logdebug("query document: %s", obj_query) # this is a list of entries in dict format including meta sort_query_dict = dc_util.string_pair_list_to_dictionary( req.sort_query) sort_query_tuples = [] for k, v in iteritems(sort_query_dict): try: sort_query_tuples.append((k, int(v))) except ValueError: sort_query_tuples.append((k, v)) # this is a list of entries in dict format including meta projection_query_dict = dc_util.string_pair_list_to_dictionary( req.projection_query) projection_meta_dict = dict() projection_meta_dict["_meta"] = 1 entries = dc_util.query_message(collection, obj_query, sort_query_tuples, projection_query_dict, req.single, req.limit) if projection_query_dict: meta_entries = dc_util.query_message(collection, obj_query, sort_query_tuples, projection_meta_dict, req.single, req.limit) # keep trying clients until we find an answer if self.replicate_on_write: for extra_client in self.extra_clients: if len(entries) == 0: extra_collection = extra_client[req.database][ req.collection] entries = dc_util.query_message(extra_collection, obj_query, sort_query_tuples, projection_query_dict, req.single, req.limit) if projection_query_dict: meta_entries = dc_util.query_message( extra_collection, obj_query, sort_query_tuples, projection_meta_dict, req.single, req.limit) if len(entries) > 0: rospy.loginfo("found result in extra datacentre") else: break serialised_messages = () metas = () for idx, entry in enumerate(entries): # load the class object for this type # TODO this should be the same for every item in the list, so could reuse cls = dc_util.load_class(entry["_meta"]["stored_class"]) # instantiate the ROS message object from the dictionary retrieved from the db message = dc_util.dictionary_to_message(entry, cls) # the serialise this object in order to be sent in a generic form serialised_messages = serialised_messages + ( dc_util.serialise_message(message), ) # add ObjectID into meta as it might be useful later if projection_query_dict: entry["_meta"]["_id"] = meta_entries[idx]["_id"] else: entry["_meta"]["_id"] = entry["_id"] # serialise meta metas = metas + (StringPairList([ StringPair( dc_srv.MongoQueryMsgRequest.JSON_QUERY, json.dumps(entry["_meta"], default=json_util.default)) ]), ) return [serialised_messages, metas]
def add_bool_argument(task, bool_arg): task.arguments.append(StringPair(first=Task.BOOL_TYPE, second=str(bool_arg)))